tags:

views:

112

answers:

4

Possible Duplicate:
How do you split a list into evenly sized chunks in Python?

Hello,

I'm trying to find a simpler way to do the following:

def list_split(list, size):
  result = [[]]
  while len(list) > 0:
    if len(result[-1]) >= size: result.append([])
    result[-1].append(list.pop(0))
  return result

Example usage:

>>> list_split([0, 1, 2, 3, 4, 5, 6], 2)
[[0, 1], [2, 3], [4, 5], [6]]
>>> list_split([0, 1, 2, 3, 4, 5, 6], 3)
[[0, 1, 2], [3, 4, 5], [6]]

I can't tell if there's a built-in way to do this, possibly with slicing or something.

This is similar but not the same to the post at http://stackoverflow.com/questions/2235526/how-to-split-a-list-into-a-given-number-of-sub-lists-in-python-closed

Thanks

EDIT: As is commented on by Anurag Uniyal, this is a duplicate of http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python/312467#312467, and should be closed, which I cannot do.

+1  A: 
def list_split(L, size):
    return [L[i*size:(i+1)*size] for i in range(1+((len(L)-1)//size))]

If you prefer a generator instead of a list, you can replace the brackets with parens, like so:

def list_split(L, size):
    return (L[i*size:(i+1)*size] for i in range(1+((len(L)-1)//size)))
Amber
Have you actually tried to run this code? Also, please don't name your parameter "list".
KennyTM
That doesn't work, list_split([0, 1, 2, 3, 4, 5, 6], 2) shouldn't return [[0, 1], [2], []]
CMC
Sorry, typo (forgot parens around `i+1`). Will fix.
Amber
(Kenny, the only reason for the parameter naming was to mirror the OP's defintion.)
Amber
Still doesn't work, list_split([0, 1, 2, 3, 4, 5, 6], 2) shouldn't return [[0, 1], [2, 3], [4, 5]] (see original post)
CMC
@Amber: OK, @CMC, please don't name your parameter "list".
KennyTM
@Amber: It works now@KennyTM: I realize that list is a bad name for a variable, as it is also a type, but for the sake of readability, and simplicity I changed it to list.
CMC
Please rename `list` to `L`. It's a Pythonic parameter/variable name.
Cristian Ciupitu
A: 
from itertools import izip_longest

def list_split(L, size):
    return [[j for j in i if j is not None] for i in izip_longest(*[iter(L)]*size)]

>>> list_split([0, 1, 2, 3, 4, 5, 6], 2)
[[0, 1], [2, 3], [4, 5], [6]]
>>> list_split([0, 1, 2, 3, 4, 5, 6], 3)
[[0, 1, 2], [3, 4, 5], [6]]
>>> list_split([0, 1, 2, 3, 4, 5, 6], 4)
[[0, 1, 2, 3], [4, 5, 6]]
>>> list_split([0, 1, 2, 3, 4, 5, 6], 5)
[[0, 1, 2, 3, 4], [5, 6]]
gnibbler
This is quite similar to the grouper() recipe of itertools, but the padding removal makes it look a bit convoluted.
tokland
+9  A: 

You could use slices to get subsets of a list.

Example:

>>> L = [0, 1, 2, 3, 4, 5, 6]
>>> n = 3
>>> [L[i:i+n] for i in range(0, len(L), n)]
[[0, 1, 2], [3, 4, 5], [6]]
>>>
Nick D
IMO this is the most Pythonic solution.
Tim Pietzcker
Yeah, actually, using range's step is a better way than my initial approach.
Amber
+1: Definitely the most explicit and clear way to split the list! It's also probably faster than rebuilding sub-lists through list comprehensions.
EOL
Er, this is using a comprehension, EOL.
Amber
+2  A: 

You have a simple functional solution in the itertools recipes (grouper):

http://docs.python.org/library/itertools.html#recipes

Whereas this function adds padding, you can easily write a non-padded implementation taking advantage of the (usually overlooked) iter built-in used this way: iter(callable, sentinel) -> iterator

def grouper(n, it):
  "grouper(3, 'ABCDEFG') --> ABC DEF G"
  return iter(lambda: list(itertools.islice(it, n)), [])

list(grouper(3, iter(mylist)))

These solutions are more generic because they both work with sequences and iterables (even if they are infinite).

tokland
N.B. If you forget the `iter` from `iter(mylist)`, then the iterator returned by `grouper` will never stop! So always pass an iterator to that function. If you pass a list named L, `islice(L, n)` will return the first N elements of L every time it's called. So unless L is empty, the `[]` sentinel will never be reached.
Cristian Ciupitu