Iterate through list two items at a time

Discussion in 'Python' started by Dave Dean, Jan 3, 2007.

  1. Dave Dean

    Dave Dean Guest

    Hi all,
    I'm looking for a way to iterate through a list, two (or more) items at a
    time. Basically...

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

    I'd like to be able to pull out two items at a time - simple examples would
    be:
    Create this output:
    1 2
    3 4
    5 6

    Create this list:
    [(1,2), (3,4), (5,6)]

    I want the following syntax to work, but sadly it does not:
    for x,y in myList:
    print x, y

    I can do this with a simple foreach statement in tcl, and if it's easy in
    tcl it's probably not too hard in Python.

    Thanks,
    Dave
    Dave Dean, Jan 3, 2007
    #1
    1. Advertising

  2. Dave Dean

    Dan Bishop Guest

    On Jan 2, 7:57 pm, "Dave Dean" <> wrote:
    > Hi all,
    > I'm looking for a way to iterate through a list, two (or more) items at a
    > time. Basically...
    >
    > myList = [1,2,3,4,5,6]
    >
    > I'd like to be able to pull out two items at a time...


    def pair_list(list_):
    return [list_[i:i+2] for i in xrange(0, len(list_), 2)]
    Dan Bishop, Jan 3, 2007
    #2
    1. Advertising

  3. Dave Dean

    Guest

    Few alternative solutions (other are possible), I usually use a variant
    of the first version, inside a partition function, the second variant
    is shorter when you don't have a handy partition() function and you
    don't want to import modules, and the forth one needs less memory when
    the data is very long:

    from itertools import izip, islice

    data = [1,2,3,4,5,6,7]

    for x1, x2 in (data[i:i+2] for i in xrange(0, len(data)/2*2, 2)):
    print x1, x2

    for x1, x2 in zip(data[::2], data[1::2]):
    print x1, x2

    for x1, x2 in izip(data[::2], data[1::2]):
    print x1, x2

    for x1, x2 in izip(islice(data,0,None,2), islice(data,1,None,2)):
    print x1, x2

    Bye,
    bearophile
    , Jan 3, 2007
    #3
  4. Dave Dean

    Guest


    >> I'm looking for a way to iterate through a list, two (or more) items
    >> at a time. Basically...
    >>
    >> myList = [1,2,3,4,5,6]
    >>
    >> I'd like to be able to pull out two items at a time...


    Dan> def pair_list(list_):
    Dan> return [list_[i:i+2] for i in xrange(0, len(list_), 2)]

    Here's another way (seems a bit clearer to me, but each person has their own
    way of seeing things):

    >>> import string
    >>> string.letters

    'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    >>> zip(string.letters[::2], string.letters[1::2])

    [('a', 'b'), ('c', 'd'), ..., ('W', 'X'), ('Y', 'Z')]

    It extends readily to longer groupings:

    >>> zip(string.letters[::3], string.letters[1::3], string.letters[2::3])

    [('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'h', 'i'), ...

    Obviously, if your lists are long, you can substitute itertools.izip for
    zip. There's probably some easy way to achieve the same result with
    itertools.groupby, but I'm out of my experience there...

    Skip
    , Jan 3, 2007
    #4
  5. At Tuesday 2/1/2007 22:57, Dave Dean wrote:

    > myList = [1,2,3,4,5,6]
    >
    >I'd like to be able to pull out two items at a time - simple examples would
    >be:
    >Create this output:
    >1 2
    >3 4
    >5 6


    b=iter(a)
    for x in b:
    y=b.next()
    print x,y

    b=iter(a)
    for x,y in ((item, b.next()) for item in b):
    print x,y

    >Create this list:
    >[(1,2), (3,4), (5,6)]


    b=iter(a)
    [(item, b.next()) for item in b]

    Note that they don't behave the same at the corner cases (empty list,
    single item, odd length...)


    --
    Gabriel Genellina
    Softlab SRL






    __________________________________________________
    Preguntá. Respondé. Descubrí.
    Todo lo que querías saber, y lo que ni imaginabas,
    está en Yahoo! Respuestas (Beta).
    ¡Probalo ya!
    http://www.yahoo.com.ar/respuestas
    Gabriel Genellina, Jan 3, 2007
    #5
  6. Dave Dean wrote:

    > I'm looking for a way to iterate through a list, two (or more) items at a
    > time.


    Here's a solution, from the iterools documentation. It may not be the /most/
    beautiful, but it is short, and scales well for larger groupings:

    >>> from itertools import izip
    >>> def groupn(iterable, n):

    .... return izip(* [iter(iterable)] * n)
    ....
    >>> list(groupn(myList, 2))

    [(0, 1), (2, 3), (4, 5), (6, 7), (8, 9), (10, 11)]
    >>> list(groupn(myList, 3))

    [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11)]
    >>> list(groupn(myList, 4))

    [(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)]
    >>> for a,b in groupn(myList, 2):

    .... print a, b
    ....
    0 1
    2 3
    4 5
    6 7
    8 9
    10 11
    >>>


    Jeffrey
    Jeffrey Froman, Jan 3, 2007
    #6
  7. Dave Dean

    Dave Dean Guest

    Thanks for all the fast responses. I'm particularly a fan of the zip
    method, followed closely by the xrange example. All, of course, are a lot
    of help!
    Thanks,
    Dave
    Dave Dean, Jan 3, 2007
    #7
  8. Dave Dean wrote:

    > Hi all,
    > I'm looking for a way to iterate through a list, two (or more) items at a
    > time. Basically...
    >
    > myList = [1,2,3,4,5,6]
    >
    > I'd like to be able to pull out two items at a time - simple examples would
    > be:
    > Create this output:
    > 1 2
    > 3 4
    > 5 6
    >
    > Create this list:
    > [(1,2), (3,4), (5,6)]
    >


    A "padding generator" version:

    def chunk( seq, size, pad=None ):
    '''
    Slice a list into consecutive disjoint 'chunks' of
    length equal to size. The last chunk is padded if necessary.

    >>> list(chunk(range(1,10),3))

    [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    >>> list(chunk(range(1,9),3))

    [[1, 2, 3], [4, 5, 6], [7, 8, None]]
    >>> list(chunk(range(1,8),3))

    [[1, 2, 3], [4, 5, 6], [7, None, None]]
    >>> list(chunk(range(1,10),1))

    [[1], [2], [3], [4], [5], [6], [7], [8], [9]]
    >>> list(chunk(range(1,10),9))

    [[1, 2, 3, 4, 5, 6, 7, 8, 9]]
    >>> for X in chunk([],3): print X
    >>>

    '''
    n = len(seq)
    mod = n % size
    for i in xrange(0, n-mod, size):
    yield seq[i:i+size]
    if mod:
    padding = [pad] * (size-mod)
    yield seq[-mod:] + padding

    ------------------------------------------------------------------

    Gerard
    Gerard Flanagan, Jan 3, 2007
    #8
  9. Gabriel Genellina wrote:
    > b=iter(a)
    > for x in b:
    > y=b.next()
    > print x,y
    >


    So as not to choke on odd-length lists, you could try

    a = [1,2,3,4,5,6,7]
    b = iter(a)
    for x in b:
    try:
    y=b.next()
    except StopIteration:
    y=None
    print x,y

    Substitute in whatever for y=None that you like.

    Cheers,
    Cliff
    J. Clifford Dyer, Jan 3, 2007
    #9
  10. Jeffrey Froman wrote:
    > Dave Dean wrote:
    >
    > > I'm looking for a way to iterate through a list, two (or more) items at a
    > > time.

    >
    > Here's a solution, from the iterools documentation. It may not be the /most/
    > beautiful, but it is short, and scales well for larger groupings:
    >
    > >>> from itertools import izip
    > >>> def groupn(iterable, n):

    > ... return izip(* [iter(iterable)] * n)
    > ...
    > >>> list(groupn(myList, 2))

    > [(0, 1), (2, 3), (4, 5), (6, 7), (8, 9), (10, 11)]
    > >>> list(groupn(myList, 3))

    > [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11)]
    > >>> list(groupn(myList, 4))

    > [(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)]
    > >>> for a,b in groupn(myList, 2):

    > ... print a, b
    > ...
    > 0 1
    > 2 3
    > 4 5
    > 6 7
    > 8 9
    > 10 11
    > >>>

    >
    > Jeffrey


    This works great except you lose any 'remainder' from myList:

    >>> list(groupn(range(10),3))

    [(0, 1, 2), (3, 4, 5), (6, 7, 8)] # did not include (9,)

    The following might be more complex than necessary but it solves the
    problem, and like groupn()
    it works on infinite lists.

    from itertools import groupby, imap
    def chunk(it, n=0):
    if n == 0:
    return iter([it])
    grouped = groupby(enumerate(it), lambda x: int(x[0]/n))
    counted = imap(lambda x:x[1], grouped)
    return imap(lambda x: imap(lambda y: y[1], x), counted)

    >>> [list(x) for x in chunk(range(10), 3)]

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

    Note the chunks are iterators, not tuples as in groupn():

    >>> [x for x in chunk(range(10), 3)]

    [<itertools.imap object at 0xb78d4c4c>,
    <itertools.imap object at 0xb78d806c>,
    <itertools.imap object at 0xb78d808c>,
    <itertools.imap object at 0xb78d4c6c>]


    -- Wade Leftwich
    Ithaca, NY
    Wade Leftwich, Jan 4, 2007
    #10
  11. Wade Leftwich wrote:
    > Jeffrey Froman wrote:
    > > Dave Dean wrote:
    > >
    > > > I'm looking for a way to iterate through a list, two (or more) items at a
    > > > time.

    > >
    > > Here's a solution, from the iterools documentation. It may not be the /most/
    > > beautiful, but it is short, and scales well for larger groupings:
    > >
    > > >>> from itertools import izip
    > > >>> def groupn(iterable, n):

    > > ... return izip(* [iter(iterable)] * n)
    > > ...
    > > >>> list(groupn(myList, 2))

    > > [(0, 1), (2, 3), (4, 5), (6, 7), (8, 9), (10, 11)]
    > > >>> list(groupn(myList, 3))

    > > [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11)]
    > > >>> list(groupn(myList, 4))

    > > [(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)]
    > > >>> for a,b in groupn(myList, 2):

    > > ... print a, b
    > > ...
    > > 0 1
    > > 2 3
    > > 4 5
    > > 6 7
    > > 8 9
    > > 10 11
    > > >>>

    > >
    > > Jeffrey

    >
    > This works great except you lose any 'remainder' from myList:
    >
    > >>> list(groupn(range(10),3))

    > [(0, 1, 2), (3, 4, 5), (6, 7, 8)] # did not include (9,)
    >
    > The following might be more complex than necessary but it solves the
    > problem, and like groupn()
    > it works on infinite lists.
    >
    > from itertools import groupby, imap
    > def chunk(it, n=0):
    > if n == 0:
    > return iter([it])
    > grouped = groupby(enumerate(it), lambda x: int(x[0]/n))
    > counted = imap(lambda x:x[1], grouped)
    > return imap(lambda x: imap(lambda y: y[1], x), counted)
    >
    > >>> [list(x) for x in chunk(range(10), 3)]

    > [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
    >
    > Note the chunks are iterators, not tuples as in groupn():
    >
    > >>> [x for x in chunk(range(10), 3)]

    > [<itertools.imap object at 0xb78d4c4c>,
    > <itertools.imap object at 0xb78d806c>,
    > <itertools.imap object at 0xb78d808c>,
    > <itertools.imap object at 0xb78d4c6c>]
    >
    >
    > -- Wade Leftwich
    > Ithaca, NY


    Or, using generator expressions instead of imap and getting rid of the
    lambdas --

    from itertools import groupby

    def chunk(it, n=0):
    if n == 0:
    return iter([it])
    def groupfun((x,y)):
    return int(x/n)
    grouped = groupby(enumerate(it), groupfun)
    counted = (y for (x,y) in grouped)
    return ((z for (y,z) in x) for x in counted)

    >>> [list(x) for x in chunk(range(10), 3)]

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

    >>> [x for x in chunk(range(10), 3)]

    [<generator object at 0xb7a34e4c>,
    <generator object at 0xb7a34dac>,
    <generator object at 0xb7a34d2c>,
    <generator object at 0xb7a34d6c>]
    Wade Leftwich, Jan 4, 2007
    #11
  12. Dave Dean

    Peter Otten Guest

    Wade Leftwich wrote:

    > from itertools import groupby
    >
    > def chunk(it, n=0):
    > if n == 0:
    > return iter([it])
    > def groupfun((x,y)):
    > return int(x/n)
    > grouped = groupby(enumerate(it), groupfun)
    > counted = (y for (x,y) in grouped)
    > return ((z for (y,z) in x) for x in counted)
    >
    >>>> [list(x) for x in chunk(range(10), 3)]

    > [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
    >
    >>>> [x for x in chunk(range(10), 3)]

    > [<generator object at 0xb7a34e4c>,
    > <generator object at 0xb7a34dac>,
    > <generator object at 0xb7a34d2c>,
    > <generator object at 0xb7a34d6c>]


    Note that all but the last of these generators are useless:

    >>> chunks = [x for x in chunk(range(10), 3)]
    >>> [list(x) for x in chunks]

    [[], [], [], [9]] # did you expect that?

    Peter
    Peter Otten, Jan 4, 2007
    #12
  13. Peter Otten wrote:
    > Wade Leftwich wrote:
    >
    > > from itertools import groupby
    > >
    > > def chunk(it, n=0):
    > > if n == 0:
    > > return iter([it])
    > > def groupfun((x,y)):
    > > return int(x/n)
    > > grouped = groupby(enumerate(it), groupfun)
    > > counted = (y for (x,y) in grouped)
    > > return ((z for (y,z) in x) for x in counted)
    > >
    > >>>> [list(x) for x in chunk(range(10), 3)]

    > > [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
    > >
    > >>>> [x for x in chunk(range(10), 3)]

    > > [<generator object at 0xb7a34e4c>,
    > > <generator object at 0xb7a34dac>,
    > > <generator object at 0xb7a34d2c>,
    > > <generator object at 0xb7a34d6c>]

    >
    > Note that all but the last of these generators are useless:
    >
    > >>> chunks = [x for x in chunk(range(10), 3)]
    > >>> [list(x) for x in chunks]

    > [[], [], [], [9]] # did you expect that?
    > In [48]: chunkgen = chunk(range(10), 3)


    In [49]: for x in chunkgen:
    ....: print list(x)
    ....:
    ....:
    [0, 1, 2]
    [3, 4, 5]
    [6, 7, 8]
    [9]

    > Peter


    That's an interesting gotcha that I've never run into when using this
    function, because in practice I never put the generator returned by
    chunk() inside a list comprehension.

    In [51]: chunkgen = chunk(range(10), 3)

    In [52]: [list(x) for x in chunkgen]
    Out[52]: [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

    But, as you pointed out --

    In [57]: chunkgen = chunk(range(10), 3)

    In [58]: chunks = list(chunkgen)

    In [59]: [list(x) for x in chunks]
    Out[59]: [[], [], [], [9]]

    So apparently when we list(chunkgen), we are exhausting the generators
    that are its members. And if we do it again, we get rid of the [9] --

    In [60]: [list(x) for x in chunks]
    Out[60]: [[], [], [], []]

    I'll admit that chunk() is needlessly tricky for most purposes. I wrote
    it to accept a really lengthy, possibly unbounded, iterator and write
    out 10,000-line files from it, and also to play with Python's new
    functional capabilities.

    -- Wade
    Wade Leftwich, Jan 4, 2007
    #13
    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. Do
    Replies:
    2
    Views:
    2,947
  2. Gogo
    Replies:
    1
    Views:
    2,096
    Sudsy
    Sep 4, 2003
  3. runescience
    Replies:
    0
    Views:
    1,453
    runescience
    Feb 9, 2006
  4. Anjan Bhowmik
    Replies:
    1
    Views:
    468
    Misbah Arefin
    Feb 14, 2008
  5. John
    Replies:
    4
    Views:
    908
    RedGrittyBrick
    Apr 1, 2008
Loading...

Share This Page