better way to write this function

K

Kelie

Hello,

This function does I what I want. But I'm wondering if there is an
easier/better way. To be honest, I don't have a good understanding of
what "pythonic" means yet.

def divide_list(lst, n):
"""Divide a list into a number of lists, each with n items. Extra
items are
ignored, if any."""
cnt = len(lst) / n
rv = [[None for i in range(n)] for i in range(cnt)]
for i in range(cnt):
for j in range(n):
rv[j] = lst[i * n + j]
return rv

Thanks!
 
P

Peter Otten

Kelie said:
Hello,

This function does I what I want. But I'm wondering if there is an
easier/better way. To be honest, I don't have a good understanding of
what "pythonic" means yet.

def divide_list(lst, n):
"""Divide a list into a number of lists, each with n items. Extra
items are
ignored, if any."""
cnt = len(lst) / n
rv = [[None for i in range(n)] for i in range(cnt)]
for i in range(cnt):
for j in range(n):
rv[j] = lst[i * n + j]
return rv


You can use slicing:
.... return [items[start:start+n] for n in range(0, len(items)-n+1, n)]
.... .... print chunks(range(5), i)
....
[[0], [1], [2], [3], [4]]
[[0, 1], [2, 3]]
[[0, 1, 2]]
[[0, 1, 2, 3]]
[[0, 1, 2, 3, 4]]
[]
[]
[]
[]

Or build a generator that works with arbitrary iterables:
.... items = iter(items)
.... while 1:
.... chunk = list(islice(items, n-1))
.... chunk.append(items.next())
.... yield chunk
.... [[0, 1], [2, 3]]

Peter
 
C

Chris

Hello,

This function does I what I want. But I'm wondering if there is an
easier/better way. To be honest, I don't have a good understanding of
what "pythonic" means yet.

def divide_list(lst, n):
"""Divide a list into a number of lists, each with n items. Extra
items are
ignored, if any."""
cnt = len(lst) / n
rv = [[None for i in range(n)] for i in range(cnt)]
for i in range(cnt):
for j in range(n):
rv[j] = lst[i * n + j]
return rv

Thanks!


x = ['1', '2', '3', '4', '5', '6', '7', '8']
def divide_list(lst, n):
rv = []
for i in range(int(round((len(lst)/n),0))):
rv.append(lst[i*n:(i+1)*n])
return rv

tmp = divide_list(x, 3)
tmp
[['1', '2', '3'], ['4', '5', '6']]

One way to do it.
 
P

Paul Rubin

Chris said:
for i in range(int(round((len(lst)/n),0))): ...

Ugh!!! Not even correct (under future division), besides being ugly.
I think you mean:

for i in xrange(len(lst) // n): ...

Really though, this grouping function gets reimplemented so often that
it should be built into the stdlib, maybe in itertools.
 
C

Chris

Ugh!!! Not even correct (under future division), besides being ugly.
I think you mean:

for i in xrange(len(lst) // n): ...

Really though, this grouping function gets reimplemented so often that
it should be built into the stdlib, maybe in itertools.

Beauty is in the eye of the beholder, but true... Looks crap :p
 
P

Paul Rudin

Kelie said:
Hello,

This function does I what I want. But I'm wondering if there is an
easier/better way. To be honest, I don't have a good understanding of
what "pythonic" means yet.

def divide_list(lst, n):
"""Divide a list into a number of lists, each with n items. Extra
items are
ignored, if any."""
cnt = len(lst) / n
rv = [[None for i in range(n)] for i in range(cnt)]
for i in range(cnt):
for j in range(n):
rv[j] = lst[i * n + j]
return rv

Thanks!


See the last recipe from:
http://docs.python.org/lib/itertools-recipes.html. It's not doing
quite the same thing, but gives an illustration of one way to approach
this sort of thing.
 
K

Kelie

Really though, this grouping function gets reimplemented so often that
it should be built into the stdlib, maybe in itertools.

thanks Paul.
itertools? that was actually the first module i checked.
 
C

Chris Mellon

Kelie said:
Hello,

This function does I what I want. But I'm wondering if there is an
easier/better way. To be honest, I don't have a good understanding of
what "pythonic" means yet.

def divide_list(lst, n):
"""Divide a list into a number of lists, each with n items. Extra
items are
ignored, if any."""
cnt = len(lst) / n
rv = [[None for i in range(n)] for i in range(cnt)]
for i in range(cnt):
for j in range(n):
rv[j] = lst[i * n + j]
return rv

Thanks!


See the last recipe from:
http://docs.python.org/lib/itertools-recipes.html. It's not doing
quite the same thing, but gives an illustration of one way to approach
this sort of thing.


The one in the sample consumes the entire sequence up front, too. It's
trivial to write a fully generator based one (and only slightly more
work to implement an iterator that doesn't rely on generators, if you
want to avoid the slight performance hit), but there's a few subtle
issues and I too think that we really should have a good one ready for
use in itertools. Maybe I should write a patch.
 
R

Ricardo Aráoz

Peter said:
Kelie said:
Hello,

This function does I what I want. But I'm wondering if there is an
easier/better way. To be honest, I don't have a good understanding of
what "pythonic" means yet.

def divide_list(lst, n):
"""Divide a list into a number of lists, each with n items. Extra
items are
ignored, if any."""
cnt = len(lst) / n
rv = [[None for i in range(n)] for i in range(cnt)]
for i in range(cnt):
for j in range(n):
rv[j] = lst[i * n + j]
return rv


You can use slicing:
... return [items[start:start+n] for n in range(0, len(items)-n+1, n)]
... ... print chunks(range(5), i)
...
[[0], [1], [2], [3], [4]]
[[0, 1], [2, 3]]
[[0, 1, 2]]
[[0, 1, 2, 3]]
[[0, 1, 2, 3, 4]]
[]
[]
[]
[]



This won't work(e.g. you don't define "start", you change the value of n
through the loop). I guess you meant :

def chunks(items, n) :
return [items[i:i+n] for i in range(0, len(items)-n+1, n)]
 
P

Paul McGuire

Hello,

This function does I what I want. But I'm wondering if there is an
easier/better way. To be honest, I don't have a good understanding of
what "pythonic" means yet.

def divide_list(lst, n):
"""Divide a list into a number of lists, each with n items. Extra
items are
ignored, if any."""
cnt = len(lst) / n
rv = [[None for i in range(n)] for i in range(cnt)]
for i in range(cnt):
for j in range(n):
rv[j] = lst[i * n + j]
return rv

Thanks!

.... print j,':',[lst[i:i+j] for i in xrange(0,len(lst),j)]
....
1 : [['A'], ['B'], ['C'], ['D'], ['E']]
2 : [['A', 'B'], ['C', 'D'], ['E']]
3 : [['A', 'B', 'C'], ['D', 'E']]
4 : [['A', 'B', 'C', 'D'], ['E']]
5 : [['A', 'B', 'C', 'D', 'E']]

Or if you want to discard the uneven leftovers:
.... print j,':',[lst[i:i+j] for i in xrange(0,len(lst),j) if i
+j<=len(lst)]
....
1 : [['A'], ['B'], ['C'], ['D'], ['E']]
2 : [['A', 'B'], ['C', 'D']]
3 : [['A', 'B', 'C']]
4 : [['A', 'B', 'C', 'D']]
5 : [['A', 'B', 'C', 'D', 'E']]

Or define a lambda:
chunksWithLeftovers = lambda lst,n: [lst[i:i+n] for i in xrange(0,len(lst),n)]
chunksWithoutLeftovers = lambda lst,n: [lst[i:i+n] for i in xrange(0,len(lst),n) if i+n<=len(lst)]
chunksWithLeftovers(lst,2) [['A', 'B'], ['C', 'D'], ['E']]
chunksWithoutLeftovers(lst,2)
[['A', 'B'], ['C', 'D']]


-- Paul
 
P

Paul Hankin

Hello,

This function does I what I want. But I'm wondering if there is an
easier/better way. To be honest, I don't have a good understanding of
what "pythonic" means yet.

def divide_list(lst, n):
"""Divide a list into a number of lists, each with n items. Extra
items are
ignored, if any."""
cnt = len(lst) / n
rv = [[None for i in range(n)] for i in range(cnt)]
for i in range(cnt):
for j in range(n):
rv[j] = lst[i * n + j]
return rv

Thanks!


Here's a terrible way to do it:

def divide_list(lst, n):
return zip(*[lst[i::n] for i in range(n)])

[It produces a list of tuples rather than a list of lists, but it
usually won't matter].
 
P

Peter Otten

Peter said:
... return [items[start:start+n] for n in range(0, len(items)-n+1, n)]

Ouch, this should be

def chunks(items, n):
return [items[start:start+n] for start in range(0, len(items)-n+1, n)]

Peter
 
A

Arnaud Delobelle

... items = iter(items)
... while 1:
... chunk = list(islice(items, n-1))
... chunk.append(items.next())
... yield chunk
...>>> list(chunks(range(5), 2))

[[0, 1], [2, 3]]

Peter[/QUOTE]

I was about to send this before I saw your post :)
Well here it is anyway...
Using the fact that StopIteration exceptions fall through list
comprehensions (as opposed to islices):

def chunks(iterable, size):
next = iter(iterable).next
while True:
yield [next() for i in xrange(size)]
 
P

Peter Otten

Ricardo said:
Peter Otten wrote:
You can use slicing:
def chunks(items, n):
... return [items[start:start+n] for n in range(0, len(items)-n+1, n)]
...
for i in range(1,10):
... print chunks(range(5), i)
...
[[0], [1], [2], [3], [4]]
[[0, 1], [2, 3]]
[[0, 1, 2]]
[[0, 1, 2, 3]]
[[0, 1, 2, 3, 4]]
[]
[]
[]
[]


This won't work(e.g. you don't define "start", you change the value of n
through the loop). I guess you meant :

def chunks(items, n) :
return [items[i:i+n] for i in range(0, len(items)-n+1, n)]

Indeed; I'm still wondering how I managed to copy'n'paste the version with
the typo together with the demo of the correct one.

Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top