Velocity Reviews > a sequence question

# a sequence question

Chris Wright
Guest
Posts: n/a

 01-28-2005
Hi,

1) I want to iterate over a list "N at a time"
sort of like:

# Two at a time... won't work, obviously

>>> for a, b in [1,2,3,4]:

.... print a,b
....
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
TypeError: unpack non-sequence
>>>

Is there a nifty way to do with with list comprehensions,
or do I just have to loop over the list ?

cheers and thanks

chris wright

Diez B. Roggisch
Guest
Posts: n/a

 01-28-2005
l = [1,2,3,4]

for a, b in zip(l[::2], l[1::2]):
print a,b

--
Regards,

Diez B. Roggisch

Roy Smith
Guest
Posts: n/a

 01-28-2005
In article <lzrKd.138680\$(E-Mail Removed)>,
Chris Wright <(E-Mail Removed)> wrote:

> Hi,
>
> 1) I want to iterate over a list "N at a time"

You could do it with slicing and zip:

>>> l = [1, 2, 3, 4, 5, 6, 7, 8]
>>> zip (l[::2], l[1::2])

[(1, 2), (3, 4), (5, 6), (7, ]

To my eyes, that's a bit cryptic, but it works and it's certainly
compact. I don't use either zip() or extended slicing a lot; perhaps if
I used them more often, the above would be more obvious to me if I read
it in somebody else's code.

The interesting thing would be generalizing this to the "N at a time"
case. I think this works:

def nzip (list0, n):
args = []
for i in range(n):
slice = list0[i::n]
args.append (slice)
return zip (*args)

l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
print nzip (l, 3)

Roy-Smiths-Computerlay\$ ./nzip.py
[(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12)]

but I haven't given any thought to what happens if the length of the
list isn't a multiple of n (exercise for the reader). It's also
annoying that the above generates a bunch of temporary lists. It would
be cool if there was a way to have the intermediates be generator
expressions, but I'm not that good with that stuff, so I'll leave that
as an exercise for other readers

F. Petitjean
Guest
Posts: n/a

 01-28-2005
Le Fri, 28 Jan 2005 13:59:45 GMT, Chris Wright a écrit :
> Hi,
>
> 1) I want to iterate over a list "N at a time"
>
>
> Is there a nifty way to do with with list comprehensions,
> or do I just have to loop over the list ?
>
> cheers and thanks

seq = xrange(1, 9) # an iterable [1, 2, ... 8]
N = 2
it = (iter(seq,)*N # a tuple containing N times the *same* iterator on
seq
print zip(*it) # the list you are after
from itertools import izip
help(izip)
it = (iter(seq),)*2
for tup in izip(*it):
print tup
>
> chris wright

Duncan Booth
Guest
Posts: n/a

 01-28-2005
Chris Wright wrote:

> 1) I want to iterate over a list "N at a time"
> sort of like:
>
> # Two at a time... won't work, obviously
>
> >>> for a, b in [1,2,3,4]:

> ... print a,b
> ...

Try this:

l = [1, 2, 3, 4]
for a, b in zip(*[iter(l)]*2):
print a, b

zip(*[iter(seq)]*N) will group by N (but if there are any odd items at the
end it will ignore them).

map(None, *[iter(seq)]*N) will group by N padding the last item with None
if it needs to.

Michael Hartl
Guest
Posts: n/a

 01-28-2005
For problems like this I use a partition function defined in a utils.py
file that I use (based on Peter Norvig's utils file at
http://aima.cs.berkeley.edu/python/utils.py). Using partition, the
problem you posed can be solved by writing

#for a, b in partition([1, 2, 3, 4], 2):
# print a, b

The implementation of partition I use is simple-minded; the previous
posts in this thread suggest some more sophisticated ways to attack it
using generators.

#def partition(seq, partsize):
# """Partition a sequence into subsequences of length partsize."""
# ls = len(seq)
# assert ls % partsize == 0, ('length %s, partition size %s\n'
# % (ls, partsize))
# return [seq[ii+partsize)] for i in range(0, ls, partsize)]
Michael

Nick Coghlan
Guest
Posts: n/a

 01-29-2005
Duncan Booth wrote:
> Try this:
>
> l = [1, 2, 3, 4]
> for a, b in zip(*[iter(l)]*2):
> print a, b
>
> zip(*[iter(seq)]*N) will group by N (but if there are any odd items at the
> end it will ignore them).
>
> map(None, *[iter(seq)]*N) will group by N padding the last item with None
> if it needs to.

For anyone else who was as bemused as I was that Duncan's and F. Petitjean's
suggestions actually *work*, this was what I had to do to figure out *why* they
work:

Py> l = [1, 2, 3, 4]
Py> itr = iter(l)
Py> zip(itr) # Put all items from iterator in position 1
[(1,), (2,), (3,), (4,)]
Py> itr = iter(l)
Py> zip(itr, itr) # Put every second item in position 2
[(1, 2), (3, 4)]

Using zip(*[iter(l)]*N) or zip(*(iter(l),)*N) simply extends the above to the
general case.

I'd definitely recommend hiding this trick inside a function. Perhaps something
like (using Michael's function name):

from itertools import izip, repeat, chain

def partition(seq, part_len):
return izip(*((iter(seq),) * part_len))

itr = iter(seq)
if (len(seq) % part_len != 0):
return izip(*((itr,) * part_len))

Py> list(partition(range(10), 2))
[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]
Py> list(partition(range(10), 3))
[(0, 1, 2), (3, 4, 5), (6, 7, ]
[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]
[(0, 1, 2), (3, 4, 5), (6, 7, , (9, None, None)]
[(0, 1, 2), (3, 4, 5), (6, 7, , (9, False, False)]
[(0, 3, 6, 9), (1, 4, 7, None), (2, 5, 8, None)]

Not sure how useful that last example is, but I thought it was cute

Cheers,
Nick.

--
Nick Coghlan | http://www.velocityreviews.com/forums/(E-Mail Removed) | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net

gene.tani@gmail.com
Guest
Posts: n/a

Steven Bethard
Guest
Posts: n/a

 02-01-2005
Nick Coghlan wrote:
> I'd definitely recommend hiding this trick inside a function. Perhaps
> something like (using Michael's function name):
>
> from itertools import izip, repeat, chain
>
> def partition(seq, part_len):
> return izip(*((iter(seq),) * part_len))
>
> itr = iter(seq)
> if (len(seq) % part_len != 0):
> return izip(*((itr,) * part_len))

I think you can write that second one so that it works for iterables
without a __len__:

.... itr = itertools.chain(
.... iter(iterable), itertools.repeat(pad_val, part_len - 1))
.... return itertools.izip(*[itr]*part_len)
....
[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]
[(0, 1, 2), (3, 4, 5), (6, 7, , (9, None, None)]

I just unconditionally pad the iterable with 1 less than the partition
size... I think that works right, but I haven't tested it any more than
what's shown.

Steve

todddeluca@gmail.com
Guest
Posts: n/a

 02-01-2005

Chris Wright wrote:
> Hi,
>
> 1) I want to iterate over a list "N at a time"
> sort of like:
>
> # Two at a time... won't work, obviously
>
> >>> for a, b in [1,2,3,4]:

> ... print a,b
> ...
> Traceback (most recent call last):
> File "<interactive input>", line 1, in ?
> TypeError: unpack non-sequence
> >>>

>
>
> Is there a nifty way to do with with list comprehensions,
> or do I just have to loop over the list ?
>
> cheers and thanks
>
> chris wright

I wouldn't call this nifty, but it does use list comprehensions:
(n-(len(l)%n))%n is the amount of padding
(len(l)+(n-(len(l)%n))%n)/n is the number of groups (calculated by
adding the padding to the length of l and then dividing by n)

>>> l = range(10)
>>> n = 3
>>> [(l+[None]*((n-(len(l)%n))%n))[i*ni+1)*n] for i in

xrange((len(l)+(n-(len(l)%n))%n)/n)]
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, None, None]]

Regards,
Todd

 Posting Rules You may not post new threads You may not post replies You may not post attachments You may not edit your posts BB code is On Smilies are On [IMG] code is On HTML code is OffTrackbacks are On Pingbacks are On Refbacks are Off Forum Rules

 Similar Threads Thread Thread Starter Forum Replies Last Post stef mientki Python 13 10-20-2007 10:21 AM Phillip N Rounds ASP .Net 3 03-05-2006 04:41 PM =?Utf-8?B?SmF5?= ASP .Net 3 12-21-2005 07:07 PM rajkumar@hotmail.com C++ 4 03-11-2005 01:32 AM bird Computer Support 13 12-24-2003 02:20 AM