标签云

微信群

扫码加入我们

WeChat QR Code

I wonder whether there is a shortcut to make a simple list out of list of lists in Python.I can do that in a for loop, but maybe there is some cool "one-liner"? I tried it with reduce, but I get an error.Codel = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]reduce(lambda x, y: x.extend(y), l)Error messageTraceback (most recent call last):File "<stdin>", line 1, in <module>File "<stdin>", line 1, in <lambda>AttributeError: 'NoneType' object has no attribute 'extend'


There's an in-depth discussion of this here: rightfootin.blogspot.com/2006/09/more-on-python-flatten.html, discussing several methods of flattening arbitrarily nested lists of lists. An interesting read!

2019年05月24日30分48秒

Some other answers are better but the reason yours fails is that the 'extend' method always returns None. For a list with length 2, it will work but return None. For a longer list, it will consume the first 2 args, which returns None. It then continues with None.extend(<third arg>), which causes this erro

2019年05月24日30分48秒

shawn-chin solution is the more pythonic here, but if you need to preserve the sequence type, say you have a tuple of tuples rather than a list of lists, then you should use reduce(operator.concat, tuple_of_tuples). Using operator.concat with tuples seems to perform faster than chain.from_iterables with list.

2019年05月24日30分48秒

I tried a test with the same data, using itertools.chain.from_iterable : $ python -mtimeit -s'from itertools import chain; l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'list(chain.from_iterable(l))'. It runs a bit more than twice as fast as the nested list comprehension that's the fastest of the alternatives shown here.

2019年05月24日30分48秒

I found the syntax hard to understand until I realized you can think of it exactly like nested for loops.for sublist in l: for item in sublist: yield item

2019年05月24日30分48秒

BorisChervenkov: Notice that I wrapped the call in list() to realize the iterator into a list.

2019年05月23日30分48秒

[leaf for tree in forest for leaf in tree] might be easier to comprehend and apply.

2019年05月24日30分48秒

Joel, actually nowadays list(itertools.chain.from_iterable(l)) is best -- as noticed in other comments and Shawn's answer.

2019年05月23日30分48秒

The * is the tricky thing that makes chain less straightforward than the list comprehension. You have to know that chain only joins together the iterables passed as parameters, and the * causes the top-level list to be expanded into parameters, so chain joins together all those iterables, but doesn't descend further. I think this makes the comprehension more readable than the use of chain in this case.

2019年05月23日30分48秒

TimDierks: I'm not sure "this requires you to understand Python syntax" is an argument against using a given technique in Python. Sure, complex usage could confuse, but the "splat" operator is generally useful in many circumstances, and this isn't using it in a particularly obscure way; rejecting all language features that aren't necessarily obvious to beginning users means you're tying one hand behind your back. May as well throw out list comprehensions too while you're at it; users from other backgrounds would find a for loop that repeatedly appends more obvious.

2019年05月24日30分48秒

Python 3.6+ version: [*chain.from_iterable(product(*list2d))], assuming you really need the list and can't just iterate directly over the items.

2019年05月23日30分48秒

reduce(lambda x,y: x+y,l) could be replaced with reduce(operator.add, l)

2019年05月24日30分48秒

that's pretty neat and clever but I wouldn't use it because it's confusing to read.

2019年05月24日30分48秒

This is a Shlemiel the painter's algorithm joelonsoftware.com/articles/fog0000000319.html -- unnecessarily inefficient as well as unnecessarily ugly.

2019年05月24日30分48秒

The append operation on lists forms a Monoid, which is one of the most convenient abstractions for thinking of a + operation in a general sense (not limited to numbers only). So this answer deserves a +1 from me for (correct) treatment of lists as a monoid. The performance is concerning though...

2019年05月23日30分48秒

andrewrk Well, some people think that this is the cleanest way of doing it : youtube.com/watch?v=IOiZatlZtGU the ones who do not get why this is cool just need to wait a few decades until everybody does it this way :) let's use programming languages (and abstractions) that are discovered and not invented, Monoid is discovered.

2019年05月24日30分48秒

this is a very inefficient way because of the quadratic aspect of the sum.

2019年05月24日30分48秒

For huge nested lists,' list(numpy.array(a).flat)' is the fastest among all functions above.

2019年05月23日30分48秒

reduce(operator.add, l) would be the correct way to do the reduce version. Built-ins are faster than lambdas.

2019年05月24日30分48秒

agf here is how:* timeit.timeit('reduce(operator.add, l)', 'import operator; l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]', number=10000) 0.017956018447875977 * timeit.timeit('reduce(lambda x, y: x+y, l)', 'import operator; l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]', number=10000) 0.025218963623046875

2019年05月23日30分48秒

This is a Shlemiel the painter's algorithm joelonsoftware.com/articles/fog0000000319.html

2019年05月24日30分48秒

this can use only for integers. But what if list contains string?

2019年05月24日30分48秒

Freddy: The operator.add function works equally well for both lists of integers and lists of strings.

2019年05月24日30分48秒

I just wrote pretty much the same, because I didn't see your solution ... here is what I looked for"recursively flatten complete multiple lists" ... (+1)

2019年05月24日30分48秒

MartinThoma Much appreciated.FYI, if flattening nested iterables is a common practice for you, there are some third-party packages that handle this well.This may save from reinventing the wheel. I've mentioned more_itertools among others discussed in this post.Cheers.

2019年05月24日30分48秒

Maybe traverse could also be a good name for this way of a tree, whereas I'd keep it less universal for this answer by sticking to nested lists.

2019年05月24日30分48秒

You can check if hasattr(x, '__iter__') instead of importing/checking against Iterable and that will exclude strings as well.

2019年05月23日30分48秒

for a truly miniscule list, e.g. one with 3 sublists, maybe -- but since sum's performance goes with O(N**2) while the list comprehension's goes with O(N), just growing the input list a little will reverse things -- indeed the LC will be "infinitely faster" than sum at the limit as N grows. I was responsible for designing sum and doing its first implementation in the Python runtime, and I still wish I had found a way to effectively restrict it to summing numbers (what it's really good at) and block the "attractive nuisance" it offers to people who want to "sum" lists;-).

2019年05月23日30分48秒

sum no longer works on arbitrary sequences as it starts with 0, making functools.reduce(operator.add, sequences) the replacement (aren't we glad they removed reduce from builtins?). When the types are known it might be faster to use type.__add__.

2019年05月23日30分48秒

YannVernier Thanks for the information. I thought I ran these benchmarks on Python 3.6 and it worked with sum. Do you happen to know on which Python versions it stopped working?

2019年05月24日30分48秒

I was somewhat mistaken. 0 is just the default starting value, so it works if one uses the start argument to start with an empty list... but it still special cases strings and tells me to use join. It's implementing foldl instead of foldl1. The same issue pops up in 2.7.

2019年05月24日30分48秒

This probably creates many, many, intermediate lists.

2019年05月24日30分48秒

for python3 from functools import reduce

2019年05月23日30分48秒

Sorry that's really slow see rest of answers

2019年05月24日30分48秒

This is by far the easiest to understand yet short solution that works on Python 2 and 3. I realise that a lot of Python folks are in data processing where there's huge amounts of data to process and thus care a lot about speed, but when you are writing a shell script and only have a few dozen elements in a few sub-lists, then this is perfect.

2019年05月24日30分48秒

Hmm to be fair second example should be list also (or first tuple ?)

2019年05月23日30分48秒

extend is better used as newlist = [], extend = newlist.extend, for sublist in l: extend(l) as it avoids the (rather large) overhead of the lambda, the attribute lookup on x, and the or.

2019年05月24日30分48秒

def flatten(l, a=None): if a is None: a = [] [...]

2019年05月23日30分48秒

doesn't work with already flat arrays, consider: import numpy as np l = [1, 2, 3] print (np.concatenate(l))ValueError: zero-dimensional arrays cannot be concatenated

2019年05月24日30分48秒

would that be the optimal solution ?

2019年05月23日30分48秒

Similarly, you can use pydash. I find this version to be much more readable than the list comprehension or any other answers.

2019年05月23日30分48秒

This is super slow.

2019年05月24日30分48秒

Why does it have a module named _? That seems like a bad name. See stackoverflow.com/a/5893946/6605826

2019年05月23日30分48秒

EL_DON: From underscore.py readme page "Underscore.py is a python port of excellent javascript library underscore.js". I think it's the reason for this name. And yes, It's not a good name for python

2019年05月24日30分48秒

This will work only for numerical data

2019年05月24日30分48秒

This works for numerical, strings and mixed lists also

2019年05月24日30分48秒

Fails for unevenly nested data, like [1, 2, [3], [[4]], [5, [6]]]

2019年05月23日30分48秒

Fails for python2.7 for the example nested list in the question: [[1, 2, 3], [4, 5, 6], [7], [8, 9]]

2019年05月23日30分48秒

That's just a more complicated and a bit slower way of what ᴡʜᴀᴄᴋᴀᴍᴀᴅᴏᴏᴅʟᴇ3000 already posted before. I reinvented his proposal yesterday, so this approach seems quite popular these days ;)

2019年05月24日30分48秒

Not quite:wierd_list = [[1, 2, 3], [4, 5, 6], [7], [8, 9], 10] >> nice_list=[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 0]

2019年05月23日30分48秒

my code as one liner would be :flat_list = [int(e.replace('[','').replace(']','')) for e in str(deep_list).split(',')]

2019年05月24日30分48秒

You are indeed right +1, ᴡʜᴀᴄᴋᴀᴍᴀᴅᴏᴏᴅʟᴇ3000's proposal won't work with multiple digit numbers, I also didn't test this before although it should be obvious. You could simplify your code and write [int(e.strip('[ ]')) for e in str(deep_list).split(',')]. But I'd suggest to stick with Deleet's proposal for real use cases. It doesn't contain hacky type transformations, it's faster and more versatile because it naturally also handles lists with mixed types.

2019年05月23日30分48秒

Unfortunately no. But I saw this code recently here: Python Practice Book 6.1.2

2019年05月24日30分48秒

Doesn't work for unevenly nested lists like [1, 2, [3], [[4]], [5, [6]]]

2019年05月24日30分48秒

This is wrong, flatten will reduce the dimensions of the nd array to one, but not concatenate the lists inside as one.

2019年05月24日30分48秒

If you are still interested in Python 2 compatibility, change yield from to a for loop, e.g. for x in flatten(i): yield x

2019年05月24日30分48秒