Flatten list of lists [duplicate]
Asked Answered
F

4

141

I'm having a problem with square brackets in Python. I wrote a code that produces the following output:

[[180.0], [173.8], [164.2], [156.5], [147.2], [138.2]]

But I would like to perform some calculations with that, but the the square brackets won't let me.

How can I remove the brackets? I saw some examples to do that but I could not apply them to this case.

Fosse answered 29/6, 2012 at 15:32 Comment(4)
In other words, you have a list of lists and you want to be able to do work on all members of the inner lists? Also, since all of these inner lists have one value, is it worth ensuring that only the value is inserted into the outer list? Or is it possible for some of the lists to have multiple elements? It's important to give all of the possible information you can, as precisely as possible.Biagi
To help people answer your questions in the future, try to avoid general statements like "the square brackets won't let me" and instead give a specific example of something you tried to do which didn't work, and copy-and-paste a small test code showing the resulting error.Lajuanalake
related flatten nested listMotheaten
If they answered your question, you should accept one of these answersOwens
O
218

Flatten the list to "remove the brackets" using a nested list comprehension. This will un-nest each list stored in your list of lists!

list_of_lists = [[180.0], [173.8], [164.2], [156.5], [147.2], [138.2]]
flattened = [val for sublist in list_of_lists for val in sublist]

Nested list comprehensions evaluate in the same manner that they unwrap (i.e. add newline and tab for each new loop. So in this case:

flattened = [val for sublist in list_of_lists for val in sublist]

is equivalent to:

flattened = []
for sublist in list_of_lists:
    for val in sublist:
        flattened.append(val)

The big difference is that the list comp evaluates MUCH faster than the unraveled loop and eliminates the append calls!

If you have multiple items in a sublist the list comp will even flatten that. ie

>>> list_of_lists = [[180.0, 1, 2, 3], [173.8], [164.2], [156.5], [147.2], [138.2]]
>>> flattened  = [val for sublist in list_of_lists for val in sublist]
>>> flattened 
[180.0, 1, 2, 3, 173.8, 164.2, 156.5, 147.2,138.2]
Owens answered 29/6, 2012 at 15:36 Comment(10)
Using itertools.chain.from_iterable is much simpler.Biagi
Please explain why. This is about as simple as it getsOwens
Sorry, I meant more readable/intuitive. Since the OP is having trouble disambiguating between what lists are (sequences of data) and how lists are represented in code (with square brackets), I highly doubt a double list comprehension will make any sense to him/her.Biagi
+1 for being more than twice faster (time it), requires no import and is more compact-Pusey
Love this answer, but I can't figure it out. Can you talk me through how Python evaluates this list comprehension?Nickles
@Nickles I made some updates. Let me know if that clarifies this. Thanks for the suggestion.Owens
@Paul. Fantastic. Seeing it broken into blocks was enlightening.Nickles
While the question is a duplicate, I think this answer is superior to any others I've seen. I like list comprehension a lot, but this particular construct remains non-intuitive for some reason.Quinn
@Quinn I agree ... it seems like this nested list comprehension is intuitively backwards. Seems like it should be [val for val in (sublist for sublist in list_of_lists)] or something like that. But that yields the original nested list. Apparently the "nested list comprehension" here is a different structure from what I'm thinking.Uncle
This is successful for nested lists of uniform depth, but not something like ['apple', 'pie', ['ham', 'cheese']]Chryso
D
164

I would use itertools.chain - this will also cater for > 1 element in each sublist:

from itertools import chain
list(chain.from_iterable([[180.0], [173.8], [164.2], [156.5], [147.2], [138.2]]))
Deus answered 29/6, 2012 at 15:39 Comment(11)
Why would you import an entire module to do something as simple as this?Owens
@PaulSeeb simplest, generic, built-in method way of flattening an iterable of iterables... What if the sublists had 100 elements? I certainly wouldn't want to be typing the listcomp code for that one...Deus
if the sublist had 100 elements a nested list comp could still deal with this without importing an entire module. It is mostly just style and preference but personally I see the list comp as more readable as most programmers have used list comps but not all have read the entire itertools library. Not that its difficult to look up but its just one more thing.Owens
Unfortunately, chain has the same shortcoming as a list comprehension with regard to many levels of nesting (that is, it is not recursive). However, I believe itertools allows for many nice operations to be done with highly readable code, which is why I still support this answer rather than using a double list comprehension.Biagi
@PlatinumAzure I was in the middle of writing that it breaks when more than 1-level deep when the phone rang - so you beat me to it that time! I was also going to mention that if the list doesn't need to be materialised, then just looping over the iterator that chain generates could be an advantage...Deus
@JonClements Might as well. In my answer, I had been about to write an example for summing the elements using reduce. Go ahead and run with that or something similar :-)Biagi
@PlatinumAzure Do-able but ugh - Think I'll take a rain check on that one though ;)Deus
Unfortunately, this doesn't distinguish between lists and strings.Thanos
@cerin Indeed. It works on purely an iterable of iterables (as do all the other answers here). So yes, a list of strings would most likely result in a non-sensible result. However, that's a different answer which can depend on Python version and wasn't part of this question which was based on lists of single floats.Deus
I like your answer very much, but how can flatten [1,[2,3]] ?Kinlaw
This answer is more readable and also more efficient than the double list comprehension. Tested with import timeit; import itertools; list_of_lists = [list(range(10))] * 1000; timeit.timeit(lambda: [item for sub_list in list_of_lists for item in sub_list], number=10000); timeit.timeit(lambda: list(itertools.chain.from_iterable(list_of_lists)), number=10000)Lanthanum
B
27

Given

d = [[180.0], [173.8], [164.2], [156.5], [147.2], [138.2]]

and your specific question: How can I remove the brackets?

Using list comprehension :

new_d = [i[0] for i in d]

will give you this

[180.0, 173.8, 164.2, 156.5, 147.2, 138.2]

then you can access individual items with the appropriate index, e.g., new_d[0] will give you 180.0 etc which you can then use for math.

If you are going to have a collection of data, you will have some sort of bracket or parenthesis.

Note, this solution is aimed specifically at your question/problem, it doesn't provide a generalized solution. I.e., it will work for your case.

Bison answered 29/6, 2012 at 15:35 Comment(1)
The OP has little idea about lists, giving him/her this solution might cause undesirable effects if s/he wants to use it to flatten multiple elements (no error, just silently return the first...)Pusey
D
2
>>> lis=[[180.0], [173.8], [164.2], [156.5], [147.2], [138.2]]
>>> [x[0] for x in lis]
[180.0, 173.8, 164.2, 156.5, 147.2, 138.2]
Delores answered 29/6, 2012 at 15:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.