24

One may want to do the contrary of flattening a list of lists, like here: I was wondering how you can convert a flat list into a list of lists.

In numpy you could do something like:

>>> a=numpy.arange(9)
>>> a.reshape(3,3)
>>> a
array([[0, 1, 2],
   [3, 4, 5],
   [6, 7, 8]])

I was wondering how you do the opposite, and my usual solution is something like:

>>> Mylist
['a', 'b', 'c', 'd', 'e', 'f']
>>> newList = []
for i in range(0,len(Mylist),2):
...     newList.append(Mylist[i], Mylist[i+1])
>>> newList 
[['a', 'b'], ['c', 'd'], ['e', 'f']]

is there a more "pythonic" way to do it?

2
  • its is best not to use list as a variable name as there is the builtin function list() Commented Apr 12, 2012 at 13:41
  • yeap you are right, I was just editing the code fast, my original code does not look like that. Commented Apr 12, 2012 at 13:46

4 Answers 4

39
>>> l = ['a', 'b', 'c', 'd', 'e', 'f']
>>> zip(*[iter(l)]*2)
[('a', 'b'), ('c', 'd'), ('e', 'f')]

As it has been pointed out by @Lattyware, this only works if there are enough items in each argument to the zip function each time it returns a tuple. If one of the parameters has less items than the others, items are cut off eg.

>>> l = ['a', 'b', 'c', 'd', 'e', 'f','g']
>>> zip(*[iter(l)]*2)
[('a', 'b'), ('c', 'd'), ('e', 'f')]

If this is the case then it is best to use the solution by @Sven Marnach

How does zip(*[iter(s)]*n) work

Sign up to request clarification or add additional context in comments.

8 Comments

This solution only works if there are enough items to fill it, otherwise items get cut off.
Creating a generator then duplicating a reference to it; clever.
@NickT well technically it's an iterator not a generator and I can't take credit for the cleverness :)
I see that it works, but this seems scary and obscure. Is it a good idea to rely on zip accessing the two copies of iter(l) in such an order, as to produce the desired result??
To produce a list of lists: map(list,zip(*[iter(l)]*2)), or map(list,zip(*[iter(l)]*3)), etc.
|
13

This is usually done using the grouper recipe from the itertools documentation:

def grouper(n, iterable, fillvalue=None):
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return itertools.izip_longest(fillvalue=fillvalue, *args)

Example:

>>> my_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> list(grouper(2, my_list))
[('a', 'b'), ('c', 'd'), ('e', 'f'), ('g', None)]

Comments

11

Another way to create a list of lists can be simplified as shown below:

>>>MyList = ['a','b','c','d','e','f']
# Calculate desired row/col
>>>row = 3
>>>col = 2
>>>NewList = [MyList[col*i : col*(i+1)] for i in range(row)]
>>>NewList
[['a', 'b', 'c'], ['d', 'e', 'f']]

This can method can be extended to produce any row and column size. If you select row and column values such that row*col >len(MyList), the sublist (row) containing the last value in MyList will end there, and NewList will simply be filled with the appropriate number of empty lists to satisfy the row/col specifications

>>>MyList = ['a','b','c','d','e','f','g','h']
>>>row = 3
>>>col = 3
>>>NewList = [MyList[col*i : col*(i+1)] for i in range(row)]
>>>NewList
[['a', 'b', 'c'], ['d', 'e', 'f'], ['g','h']]

>>>row = 4
>>>col = 4
>>>NewList = [MyList[col*i : col*(i+1)] for i in range(row)]
[['a', 'b', 'c', 'd'], ['e', 'f', 'g','h'], [], []]

1 Comment

I guess that should be the accepted answer as the question was asking for a list of lists and not a list of tuples. Or the answer by Robert in the comment above.
0

If one prefers a list of lists, rather than a list of tuples from a flat list, then one could do this:

    a = range(20) # sample starting list 
    b = [] # new list
    c = [] # alternate new list
    # ny is length of new list. nx length of each list within it
    nx = 5; ny = 4 
    bb = 0; ee = bb + nx # option one: sliding indeces for slices.
    for ii in range(ny-1):
        bb += nx
        ee += nx
        b.append(a[bb:ee])
        c.append(a[slice(ii*nx,nx*(ii+1))]) # option two, use slice()

(I've played around with shrinking the whole for loop into one line with list comprehensions, but have not been successful. the way I've used it, slice() can almost get you there.) One possible advantage of these approaches over the others mentioned is that if your original, flat list is not an even multiple of the dimensions of your new, desired list of lists, you won't lose any data. The caveat is that the last list will be shorter than all the others, as it will contain the "leftovers". granted, neither of these methods strikes me as very pythonic.

1 Comment

I don't understand why you're using slice() in the second approach, rather than the slice syntax. Doing a calculation doesn't mean you can't use a[ii*nx:nx*(ii+1)] or whatever.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.