There is also a 6th options, using [Fliq](https://oribarilan.github.io/fliq/)
>>> from fliq import q
>>> q([[[1], 2], [3, 4]]).flatten().to_list()
[1, 2, 3, 4]
You can also control the flatten's depth:
>>> from fliq import q
>>> q([[[1], 2], [3, 4]]).flatten(max_depth=1).to_list()
[[1], 2, 3, 4]
Docs for Fliq's flatten can be found [here](https://oribarilan.github.io/fliq/reference/code_api/mapper_methods/#fliq.query.Query.flatten)
\*disclaimer - I am the author and it is just a lib I developed for fun, but it is heavily documented and tested (also for performance), so you can safely use
An iterative solution that should work with extremely deep nesting and nested lists with heterogeneous depth:
```
def flatten_list(list_obj):
while True:
flatter = []
done = True
for item in list_obj:
if isinstance(item, list):
flatter.extend(item)
done = False
else:
flatter.append(item)
if done:
return list_obj
list_obj = flatter
```
You can also use `yield from`:
```
def flatten(lol):
for item in lol:
yield from item
```
this can easily be extended to work with any level of nesting:
```
def flatten(thing):
if isinstance(thing, list):
for item in thing:
yield from flatten(thing)
else:
yield thing
```
Not quite "any" level of nesting. Eventually you'll exceed the recursion depth limit, though in most practical cases that's likely to be a non-issue.
Also, I think \`yield from flatten(thing)\` should be \`yield from flatten(item)\`
Ah, that's funny. I didn't think of using `yield from` in the depth-2 case, but I had written exactly the same thing as you for the general case: https://www.reddit.com/r/Python/comments/181yhw2/comment/kafbqzc/?utm_source=share&utm_medium=web2x&context=3
> Did I miss something?
Yep, you missed working with deeper list of lists ```[[[1], [1, 2], [[3, 4],5], 6], 9]```.
What if the list contains strings, or tuple? Do you preserve them?
And you forgot the most simple, and probably most efficient, way to flatten a list: recursion.
Recursion is neat in the general case, you are so right!
In the general case I like something like this:
```py
def flatten(obj):
if isinstance(obj, list):
for item in obj:
yield from flatten(item)
else:
yield obj
```
In the article I only focused on lists of lists, which have specifically a homogeneous, fixed depth of 2.
I don't think that particular case warrants recursion.
I don’t know enough about internals to say if using map in this fashion is better or worse in a situation where it matters, but this reads better to me personally.
```
def flat(obj):
if isinstance(obj, list):
yield from map(flat, obj)
else:
yield obj
```
That being said I almost always go the itertools / comprehension route if I need this.
Apologies for formatting, on mobile!
I might be misunderstanding something, @notreallymetho, but the code you shared doesn’t do the same thing.
Try running:
```
lst = [[[1], [1, 2], [[3, 4],5], 6], 9]
def flat(obj):
if isinstance(obj, list):
yield from map(flat, obj)
else:
yield obj
print(list(flat(lst)))
# for elem in flat(lst):
# print(list(elem))
def flatten(obj):
if isinstance(obj, list):
for item in obj:
yield from flatten(item)
else:
yield obj
print(list(flatten(lst)))
```
Your version with map, at the first level, produces an iterable where each element is a generator, but it doesn’t flatten all of them. I think what you did was wrap each atomic element in a generator.
Oops that’s what I get for mobile and not actually validating my code. You’re correct it’s slightly different in that it’s yielding a generator per iteration.
That being said, because I already said something wrong. I often see recursion in leetcode submissions using while loops instead of for (IMO for loops are often way easier to read)
This should work on >= python 3.8 though:
```
def flat(obj):
iterator = iter(obj)
while (item := next(iterator, None)) is not None:
if isinstance(item, list):
yield from flat(item)
continue
yield item
```
No worries! We all make mistakes!
And I was genuinely worries that I might've missed something in your code... It kinda looked like it should've worked 🤣
I don't really get your paragraph about `while` vs `for` loops, though. Why'd you write that `while` loop instead of the `for`?
True that! It’s why tests exist lol.
And I was mainly saying it’s an alternative way of doing the same thing. If you’ve ever used leetcode.com - if a solution can leverage recursion, while loops are often used. Especially when it comes to tree structures (binary trees for example) and whatnot.
Semantically speaking the while and for implementations are the same and offer minimal (if any) advantage over one another and really a stylistic choice.
21 Comments
ori_303@reddit
RojerGS@reddit (OP)
JamzTyson@reddit
RojerGS@reddit (OP)
steelypip@reddit
JamzTyson@reddit
notreallymetho@reddit
RojerGS@reddit (OP)
jimtk@reddit
RojerGS@reddit (OP)
notreallymetho@reddit
RojerGS@reddit (OP)
notreallymetho@reddit
RojerGS@reddit (OP)
notreallymetho@reddit
qatanah@reddit
RojerGS@reddit (OP)
qatanah@reddit
RojerGS@reddit (OP)
siddsp@reddit
RojerGS@reddit (OP)