Packing list elements into tuples

N

Nickolay Kolev

Hi all,

I have a list whose length is a multiple of 3. I want to get a list of
tuples each of which has 3 consecutive elements from the original list,
thus packing the list into smaller packets. Like this:

l = [1,2,3,4,5,6]

tups = [(1,2,3), (4,5,6)]

or

l = [1,2,3,4,5,6,7,8,9]

tups = [(1,2,3), (4,5,6), (7,8,9)]

if i can dictionaries it would be even better:


l = [1,2,3,4,5,6]

tups = [
{'first':1,'second':2,'third':3},
{'first':4,'second':5,'third':6}
]

and so on.

Any ideas?

Many thanks in advance!

Cheers,
-- Nickolay
 
R

Russell Blau

Nickolay Kolev said:
Hi all,

I have a list whose length is a multiple of 3. I want to get a list of
tuples each of which has 3 consecutive elements from the original list,
thus packing the list into smaller packets. Like this:

l = [1,2,3,4,5,6,7,8,9]

tups = [(1,2,3), (4,5,6), (7,8,9)]

How's this? :
alist [1, 2, 3, 4, 5, 6, 7, 8, 9]
tups = [tuple(alist[i:i+3]) for i in xrange(0, len(alist), 3)]
tups
[(1, 2, 3), (4, 5, 6), (7, 8, 9)]

if i can dictionaries it would be even better:


l = [1,2,3,4,5,6]

tups = [
{'first':1,'second':2,'third':3},
{'first':4,'second':5,'third':6}
]

Well, now that you've been introduced to the concept of list indexes and
list comprehensions, I think that extending it to dictionaries is fairly
simple.
 
S

Steven Bethard

Nickolay Kolev said:
l = [1,2,3,4,5,6]

tups = [(1,2,3), (4,5,6)]

My favorite idiom:
l = [1,2,3,4,5,6]
zip(*(iter(l),)*3) [(1, 2, 3), (4, 5, 6)]
l = [1,2,3,4,5,6,7,8,9]
zip(*(iter(l),)*3)
[(1, 2, 3), (4, 5, 6), (7, 8, 9)]

If you want dicts, try:
l = [1,2,3,4,5,6]
tuples = zip(*(iter(l),)*3)
labels = 'first second third'.split()
[dict(zip(labels, t)) for t in tuples]
[{'second': 2, 'third': 3, 'first': 1}, {'second': 5, 'third': 6, 'first': 4}]

Basically, you can make a dict with whatever labels you want by zipping your
labels with the appropriate tuples and calling the dict builtin.

Steve
 
S

Scott David Daniels

I kind of like:
[dict(first=lst[k], second=lst[k+1], third=lst[k+2])
for k in range(0, len(lst), 3)]

--Scott David Daniels
(e-mail address removed)
 
T

Thorsten Kampe

* Nickolay Kolev (2004-11-09 22:29 +0100)
I have a list whose length is a multiple of 3. I want to get a list of
tuples each of which has 3 consecutive elements from the original list,
thus packing the list into smaller packets. Like this:

l = [1,2,3,4,5,6]

tups = [(1,2,3), (4,5,6)]

or

l = [1,2,3,4,5,6,7,8,9]

tups = [(1,2,3), (4,5,6), (7,8,9)]

Fragment[1] from a general purpose partitioning utility:

def part(seq, slice):
""" partition seq """
return [seq[slice * index:slice * (index + 1)]
for index in range(len(seq) / slice + bool(len(seq) % slice))]

if i can dictionaries it would be even better:

l = [1,2,3,4,5,6]

tups = [
{'first':1,'second':2,'third':3},
{'first':4,'second':5,'third':6}
]

You're losing order and therfore you're attaching 'first', 'second'
and so on because you obviously need the original order. So don't use
a dictionary.


Thorsten

[1] Just for the record:
def part(seq, slice = None, modus = None):
"""
partition seq
syntax:
part(seq, boolean_function, modus = 'bool')
-> [[first_true_items], [first_false_item, remaining_items]]
part('str', 'separator', modus = 'sep') or
part('str', ['separators'], modus = 'sep')
part(list, item, modus = 'sep')
part(n, modus = 'set')
-> len([all_possible_partitions_of_[0, 1, ..., n]])
part(list, modus = 'set'
-> [all_possible_partitions_of_list]
part(seq, int, modus = 'size')
-> [seq0, seq1, ..., seqn] - where len(seq(i)) = int
part(seq, [n0, n1, ..., n(i)], modus = 'size'
-> [seq0, seq1, ..., seq(i)] - where len(seq(i)) = n(i)
"""
 
P

Peter Otten

Nickolay said:
I have a list whose length is a multiple of 3. I want to get a list  of
tuples each of which has 3 consecutive elements from the original list,
thus packing the list into smaller packets. Like this:
... dictionaries ... would be even better:
l = [1,2,3,4,5,6]

tups = [
{'first':1,'second':2,'third':3},
{'first':4,'second':5,'third':6}
]

itertools to the rescue:
[{'second': 1, 'third': 2, 'first': 0}, {'second': 4, 'third': 5, 'first':
3}]

Fun, but not recommended. There must be a simpler expression where you need
not mention len(names) explicitly - but right now I can't think of one.
Note how the nonzero len(items) % len(names) case is handled:
iter(range(5)))))))
[{'second': 1, 'third': 2, 'first': 0}, {'second': 4, 'first': 3}]

However, in real life I would rather go with Steven Bethard's two-step
approach...

Peter
 
R

Russell Blau

Nickolay Kolev said:
Nickolay Kolev wrote:

I found it in the cookbook:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/303060

It looks quite cryptic, could anyone give me some pointers at what
exactly is going on in the function?

The function contains only one significant line, which is:

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

To figure out what it is doing, take it one piece at a time. Start with a
list:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

Pick how many elements you want in each group:

Now see what the list comprehension does:
[[1, 4, 7, 10], [2, 5, 8, 11], [3, 6, 9, 12]]

So this breaks up the list into three separate lists by taking each n'th
element from the original list, then combines them. The "n" in lst[i::n]
determines how many elements will be skipped in creating each sub-list.
Unfortunately, this syntax isn't mentioned in the tutorial or the library
reference; you have to dig to find an explanation of it in
http://www.python.org/doc/2.3.4/whatsnew/section-slices.html

Let's store the result of the last step so we can see what the following
step does:
m = [lst[i::n] for i in range(n)]
zip(*m)
[(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12)]

The magic function zip() takes a list of sequences as its argument, and
returns a new list that rearranges them. Imagine the first list (m) as a
two-dimensional table in which each sub-sequence is a row; zip() goes
through the table and returns the columns as the sub-sequences. See
http://www.python.org/doc/2.3.4/lib/built-in-funcs.html (all the way at the
end).
 
S

Steven Bethard

l = [1,2,3,4,5,6]
zip(*(iter(l),)*3) [(1, 2, 3), (4, 5, 6)]
l = [1,2,3,4,5,6,7,8,9]
zip(*(iter(l),)*3)
[(1, 2, 3), (4, 5, 6), (7, 8, 9)]

Can someone explain how this works?!
[snip]

So zip() basically gets zip(iter(l), iter(l), iter(l)) , right?

Close, but note that zip(iter(l), iter(l), iter(l)) creates three
iterators to the list l, while zip(*(iter(l),)*3) uses the same
iterator at each position in the tuple.
l = [1,2,3,4,5,6]
zip(iter(l), iter(l), iter(l)) [(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5), (6, 6, 6)]
itr = iter(l)
zip(itr, itr, itr)
[(1, 2, 3), (4, 5, 6)]

Here's basically what zip ends up doing when you give it 3 names bound
to the same iterator:
itr = iter(l)
tuple1 = (itr.next(), itr.next(), itr.next())
tuple1 (1, 2, 3)
tuple2 = (itr.next(), itr.next(), itr.next())
tuple2 (4, 5, 6)
result = [tuple1, tuple2]
result
[(1, 2, 3), (4, 5, 6)]

Note that when they're not the same iterator, zip does something like:
(2, 2, 2)
....

So you just get 3 copies of the elements at each index in your list.

Hope that helped!

Steve
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top