37

A multidimensional list like l=[[1,2],[3,4]] could be converted to a 1D one by doing sum(l,[]). How does this happen?

(This doesn't work directly for higher multidimensional lists, but it can be repeated to handle those cases. For example if A is a 3D-list, then sum(sum(A),[]),[]) will flatten A to a 1D list.)

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Sayan
  • 2,662
  • 10
  • 41
  • 56
  • 5
    This will not transform *any* multidimensional list to 1D. `[[[1,2]], [[3,4]]]` becomes `[[1, 2], [3, 4]]`. – Ponkadoodle Jun 02 '10 at 22:32
  • 1
    Also note that it is unsafe to convert just _any_ sequence to 1D, since it is trivial to make sequences with a truly infinite number of dimensions: `a = []; a.append(a)`. – badp Jun 02 '10 at 22:37
  • related "Flattening a shallow list in python" http://stackoverflow.com/questions/406121/flattening-a-shallow-list-in-python – jfs Jun 03 '10 at 05:00
  • related "Flatten (an irregular) list of lists in Python" http://stackoverflow.com/questions/2158395/flatten-an-irregular-list-of-lists-in-python – jfs Jun 03 '10 at 05:01

7 Answers7

56

If your list nested is, as you say, "2D" (meaning that you only want to go one level down, and all 1-level-down items of nested are lists), a simple list comprehension:

flat = [x for sublist in nested for x in sublist]

is the approach I'd recommend -- much more efficient than summing would be (sum is intended for numbers -- it was just too much of a bother to somehow make it block all attempts to "sum" non-numbers... I was the original proposer and first implementer of sum in the Python standard library, so I guess I should know;-).

If you want to go down "as deep as it takes" (for deeply nested lists), recursion is the simplest way, although by eliminating the recursion you can get higher performance (at the price of higher complication).

This recipe suggests a recursive solution, a recursion elimination, and other approaches (all instructive, though none as simple as the one-liner I suggested earlier in this answer).

martineau
  • 119,623
  • 25
  • 170
  • 301
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • Ah I was sure I could do it using list comprehension but was messing up with the code. Thanks and a privilege! – Sayan Jun 03 '10 at 05:32
  • @alex-martelli, this solution works great but is hard for me to understand. Would you mind walking me through the order of operations that python follows when executing this solution? – NobodyMan Aug 28 '15 at 01:39
  • 3
    @NobodyMan, sure, it's just two nested loops: exactly as if within an outer statement `for sublist in nested:` you indented a further statement `for x in sublist:` and then inside it just took the leading expression `x` of the list comprehension to be appended as the next item of the new list you're building. In other words, it works exactly like any other list comprehension with two `for` clauses -- although the leading expression before the `for` clauses is in this case extremely simple:-). – Alex Martelli Aug 28 '15 at 21:53
48

sum adds a sequence together using the + operator. e.g sum([1,2,3]) == 6. The 2nd parameter is an optional start value which defaults to 0. e.g. sum([1,2,3], 10) == 16.

In your example it does [] + [1,2] + [3,4] where + on 2 lists concatenates them together. Therefore the result is [1,2,3,4]

The empty list is required as the 2nd paramter to sum because, as mentioned above, the default is for sum to add to 0 (i.e. 0 + [1,2] + [3,4]) which would result in unsupported operand type(s) for +: 'int' and 'list'

This is the relevant section of the help for sum:

sum(sequence[, start]) -> value

Returns the sum of a sequence of numbers (NOT strings) plus the value of parameter 'start' (which defaults to 0).

Note

As wallacoloo comented this is not a general solution for flattening any multi dimensional list. It just works for a list of 1D lists due to the behavior described above.

Update

For a way to flatten 1 level of nesting see this recipe from the itertools page:

def flatten(listOfLists):
    "Flatten one level of nesting"
    return chain.from_iterable(listOfLists)

To flatten more deeply nested lists (including irregularly nested lists) see the accepted answer to this question (there are also some other questions linked to from that question itself.)

Note that the recipe returns an itertools.chain object (which is iterable) and the other question's answer returns a generator object so you need to wrap either of these in a call to list if you want the full list rather than iterating over it. e.g. list(flatten(my_list_of_lists)).

Community
  • 1
  • 1
mikej
  • 65,295
  • 17
  • 152
  • 131
  • Many thanks, understood. May I ask that what is the shortest and best way to flatten a list? At present I can only think of running two nested for loops or a recursive function to do that. – Sayan Jun 02 '10 at 23:12
  • I've done a quick update to the answer with a recipe for flattening 1 level of nesting and a link to a previous SO question with a more general solution. – mikej Jun 03 '10 at 07:13
4

For any kind of multidiamentional array, this code will do flattening to one dimension :

def flatten(l):
    try:
        return flatten(l[0]) + (flatten(l[1:]) if len(l) > 1 else []) if type(l) is list else [l]
    except IndexError:
        return []
Patel Sunil
  • 441
  • 7
  • 7
2

It looks to me more like you're looking for a final answer of:

[3, 7]

For that you're best off with a list comprehension

>>> l=[[1,2],[3,4]]
>>> [x+y for x,y in l]
[3, 7]
Adam Nelson
  • 7,932
  • 11
  • 44
  • 64
  • No not really, I was trying to find a shorter/better alternative to flatten a 2D list. I am populating a list containing triplets to another list (like [[1,2,3],[4,5,6],[7,8,9]]), and I would not enter a number if it is already existing in that list. So my aim is to put something like ...Thanks anyway :) – Sayan Jun 02 '10 at 23:18
  • 1
    @Sayan Then you don't want lists, you want `set`s. – badp Jun 03 '10 at 07:20
  • Hitherto I knew nothing about Python sets. Thanks for the direction. – Sayan Jun 03 '10 at 17:12
1

I wrote a program to do multi-dimensional flattening using recursion. If anyone has comments on making the program better, you can always see me smiling:

def flatten(l):
    lf=[]
    li=[]
    ll=[]
    p=0
    for i in l:
        if type(i).__name__=='list':
           li.append(i)
        else:
           lf.append(i)
    ll=[x for i in li for x in i]
    lf.extend(ll)

    for i in lf:
        if type(i).__name__ =='list':
           #not completely flattened
           flatten(lf)
        else:
           p=p+1
           continue

    if p==len(lf):
       print(lf)
Sayan
  • 2,662
  • 10
  • 41
  • 56
  • Thank you for offering a suggestion for not relying on a certain amount of dimensions, but when the dimensions exceeded 2, I did not have much success with this ^. I had to modify to get it to work correctly, by cloning lf to lg, then when recrursively calling flatten: j = flatten(i); lg.remove(i); lg.extend(j) – Geoff Lentsch Jul 05 '18 at 15:12
1

I've written this function:

def make_array_single_dimension(l):
    l2 = []

    for x in l:
        if type(x).__name__ == "list":
            l2 += make_array_single_dimension(x)
        else:
            l2.append(x)

    return l2

It works as well!

grooveplex
  • 2,492
  • 4
  • 28
  • 30
0

The + operator concatenates lists and the starting value is [] an empty list.

jasonleonhard
  • 12,047
  • 89
  • 66