-
Notifications
You must be signed in to change notification settings - Fork 263
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add itertoolz.flatten #547
base: master
Are you sure you want to change the base?
Conversation
toolz/itertoolz.py
Outdated
|
||
|
||
def flat(level, seq): | ||
""" Flatten a possible nested sequence by n levels """ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll fill out this docstring soon.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool. Don't forget to also point to concat(seq)
, which flattens a sequence one level.
Cool! Some questions:
|
toolz/itertoolz.py
Outdated
if level < 0: | ||
raise ValueError("level must be >= 0") | ||
for item in seq: | ||
if level == 0 or not hasattr(item, '__iter__'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably better to have outside the for loop:
if level == 0:
yield from seq
return
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! That works really well.
Yes, a very good use case for
def example_descend(x):
return not isinstance(x, (str, bytes, bytearray, dict))
def flatten(level, seq, descend=None):
""" Flatten a possible nested sequence by n levels """
if not callable(descend):
raise ValueError("descend must be callable boolean function")
if level < -1:
# -1 flattens infinitely.
raise ValueError("Level must be >=0 or -1")
def flat(level, seq):
if level == 0:
yield from seq
return
for item in seq:
if isiterable(item) and descend(item):
yield from flat(level - 1, item)
else:
yield item
yield from flat(level, seq) The descend function is only called on iterable items and returns True if the iterable should be unpacked. If this looks better to you, I can go ahead and commit it. @eriknw I really appreciate the feedback. |
flat -> flatten Allow -1 to for unregulated recursion Add UDF descend function to decide if itertable invokes recursive call. Add default descend function
@eriknw I think this is ready for another review. |
ping @eriknw |
""" | ||
if level < -1: | ||
raise ValueError("Level must be >= -1") | ||
if not callable(descend): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe let users pass None
for descend
to say "I want the default value"?
if not callable(descend): | |
if descend is None: | |
descend = _default_descend | |
if not callable(descend): |
This is something I almost always recommend for default arguments, especially when the default value is private, like it is here.
Because
-
It can help code that programmatically selects the
descend
argument. -
It can help with writing wrappers of
flatten
which themselves let users pass an optionaldescend
.
An implementation of javascript's Array.flat() (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat#use_generator_function)
More flexible than the
flatten
recipe in itertools.