Skip to content

New small utility functions #881

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 20 commits into from
Jun 21, 2023
Merged

New small utility functions #881

merged 20 commits into from
Jun 21, 2023

Conversation

romanarust
Copy link
Member

What type of change is this?

  • Bug fix in a backwards-compatible manner.
  • New feature in a backwards-compatible manner.
  • Breaking change: bug fix or new feature that involve incompatible API changes.
  • Other (e.g. doc update, configuration, etc)

Checklist

Put an x in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.

  • I added a line to the CHANGELOG.md file in the Unreleased section under the most fitting heading (e.g. Added, Changed, Removed).
  • I ran all tests on my computer and it's all green (i.e. invoke test).
  • I ran lint on my computer and there are no errors (i.e. invoke lint).
  • I added new functions/classes and made them available on a second-level import, e.g. compas.datastructures.Mesh.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have added necessary documentation (if appropriate)

@romanarust romanarust requested a review from tomvanmele July 28, 2021 17:09
Copy link
Member

@beverlylytle beverlylytle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These look like useful functions when numpy is not available. I strongly encourage adding tests though.

return chain.from_iterable(list_of_lists)


def unflatten(lst, num):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function seems to be a limited version of reshape, that is, unflatten(l, num) == reshape(l, (len(l)//num), num)). I would suggest for the sake of not cluttering the API that this should be removed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -185,10 +189,79 @@ def linspace(start, stop, num=50):


def flatten(list_of_lists):
"""Flatten one level of nesting"""
"""Flatten one level of nesting.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since numpy's flatten doesn't flatten just one level, I think this name might be confusing. So I would suggest either renaming this function or replacing it with something that behaves as numpy.flatten does. Eg

def flatten(l):
    if not hasattr(l[0], '__len__'):
        return l
    return flatten(list(chain(*l)))

Copy link
Member

@tomvanmele tomvanmele Aug 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have the feeling this will break a lot of existing code. for example, in case flatten is used on a list of lists of points, the new version will basically return a list of floats, and that is not the case with the previous version.

for point in flatten(list_of_polylines):
    # point is a point in the old version
    # point is a coordinate in the new version

----------
lst : list
A list of items.
shape : int or tuple of ints
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it makes sense for shape to be an int. As it is now, that would result in a TypeError, but I don't think it really makes sense to call reshape([1,2,3], 3). It would make sense if the input were something more complicated than a flat list. You could address this by using the version of flatten suggested above and then recursively calling a helper function which does what reshape currently does, but maybe that's more than you need:

def reshape(l, shape):
    def helper(l, shape):
        if len(shape) == 1:
            if len(l) % shape[0] != 0:
                raise ValueError()
            return [l[i:i + shape[0]] for i in range(0, len(l), shape[0])]
        n = reduce(mul, shape[1:])
        return [helper(lst[i * n:(i + 1) * n], shape[1:]) for i in range(len(lst) // n)]

    shape = (shape,) if instance(shape, int) else shape
    l = flatten(l)
    if len(l) != reduce(lambda x, y: x * y, shape):
        raise ValueError("ValueError: cannot reshape array of size %d into shape %s" % (len(lst), shape))
    return helper(l, shape)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for suggesting even better utility functions ;)

@romanarust
Copy link
Member Author

ok, i've implemented changes and added tests.

Copy link
Member

@beverlylytle beverlylytle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

Co-authored-by: beverlylytle <57254617+beverlylytle@users.noreply.github.com>
@beverlylytle
Copy link
Member

@romanarust is there any reason not to merge this?

Comment on lines 203 to 205
if not hasattr(list_of_lists[0], '__len__'):
return list_of_lists
return flatten(list(chain(*list_of_lists)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to discuss this because i think this is a breaking change...

Copy link
Member

@tomvanmele tomvanmele left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to make sure this is not yet merged by accident

@beverlylytle
Copy link
Member

We discussed this today in the compas dev meeting. flatten as it currently is written is used quite a lot in compas code and in particular changing it to what I suggested would flatten lists of lists of points to just a list of floats rather than the expected list of points, breaking many things. It was suggested that this new flatten be made an internal function, say _flatten or so, for use within reshape and that before the release of version 2.0 current usage of flatten would be switched to itertools.chain and the new _flatten would be made external. Does this make sense?

@romanarust
Copy link
Member Author

Ping here again! remove the changes to the "flatten" function, think it is ready now

@tomvanmele
Copy link
Member

@romanarust black is complaining

@tomvanmele tomvanmele merged commit 5531210 into main Jun 21, 2023
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants