Packing list elements into tuples

Discussion in 'Python' started by Nickolay Kolev, Nov 9, 2004.

  1. 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
    Nickolay Kolev, Nov 9, 2004
    #1
    1. Advertising

  2. Nickolay Kolev

    Russell Blau Guest

    "Nickolay Kolev" <> wrote in message
    news:cmrcqq$rv4$-bonn.de...
    > 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.


    --
    I don't actually read my hotmail account, but you can replace hotmail with
    excite if you really want to reach me.
    Russell Blau, Nov 9, 2004
    #2
    1. Advertising

  3. Nickolay Kolev wrote:

    > 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:


    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?

    Cheers,
    -- Nickolay
    Nickolay Kolev, Nov 9, 2004
    #3
  4. Nickolay Kolev <nmkolev <at> uni-bonn.de> writes:
    > 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
    Steven Bethard, Nov 9, 2004
    #4
  5. 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
    Scott David Daniels, Nov 9, 2004
    #5
  6. * 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)
    """
    Thorsten Kampe, Nov 10, 2004
    #6
  7. Nickolay Kolev

    Peter Otten Guest

    Nickolay Kolev wrote:

    > 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:

    >>> from itertools import *
    >>> names = "first second third".split()
    >>> items = range(6)
    >>> map(dict, takewhile(bool, starmap(zip, repeat((names, iter(items))))))

    [{'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:

    >>> map(dict, takewhile(bool, starmap(zip, repeat((names,

    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
    Peter Otten, Nov 10, 2004
    #7
  8. Nickolay Kolev

    Russell Blau Guest

    "Nickolay Kolev" <> wrote in message
    news:cmreif$rve$-bonn.de...
    > 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:

    >>> lst

    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

    Pick how many elements you want in each group:

    >>> n=3


    Now see what the list comprehension does:

    >>> [lst[i::n] for i in range(n)]

    [[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).


    --
    I don't actually read my hotmail account, but you can replace hotmail with
    excite if you really want to reach me.
    Russell Blau, Nov 10, 2004
    #8
  9. On Wed, 10 Nov 2004 19:00:52 +0800, Deepak Sarda <> wrote:
    >
    > > >>> 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:

    >>> itr1, itr2, itr3 = iter(l), iter(l), iter(l)
    >>> tuple1 = (itr1.next(), itr2.next(), itr3.next())
    >>> tuple1

    (1, 1, 1)
    >>> tuple2 = (itr1.next(), itr2.next(), itr3.next())
    >>> tuple2

    (2, 2, 2)
    ....

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

    Hope that helped!

    Steve
    --
    You can wordify anything if you just verb it.
    - Bucky Katt, Get Fuzzy
    Steven Bethard, Nov 10, 2004
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Adam Hartshorne
    Replies:
    2
    Views:
    363
    Nitin Motgi
    Jan 27, 2006
  2. Replies:
    5
    Views:
    537
    Thomas J. Gritzan
    Oct 6, 2006
  3. tuples within tuples

    , Oct 26, 2007, in forum: Python
    Replies:
    12
    Views:
    546
    Dennis Lee Bieber
    Oct 27, 2007
  4. xera121
    Replies:
    8
    Views:
    699
    lolmc
    Sep 30, 2009
  5. Jon Reyes
    Replies:
    18
    Views:
    215
    Mitya Sirenef
    Feb 19, 2013
Loading...

Share This Page