views:

221

answers:

3

I have a list of items (which are HTML table rows, extracted with Beautiful Soup) and I need to iterate over the list and get even and odd elements (I mean index) for each loop run. My code looks like this:

for top, bottom in izip(table[::2], table[1::2]):
    #do something with top
    #do something else with bottom

How to make this code less ugly? Or maybe is it good way to do this?

EDIT:

table[1::2], table[::2]  => table[::2], table[1::2]
A: 

Looks good. My only suggestion would be to wrap this in a function or method. That way, you can give it a name (evenOddIter()) which makes it much more readable.

Aaron Digulla
What is the difference between function and method in this context?
Mike Mazur
It depends on whether the code above is part of a class or top level. If it's in a class which gets a lot of reuse, it might make sense to use a method. When using a function, then it would be more simple to reuse outside any class but it would clutter the global namespace.
Aaron Digulla
it's in a class, but this loop is executed only in one place so I think there's need to make a method from this. thanks anyway
paffnucy
+4  A: 

izip is a pretty good option, but here's a few alternatives since you're unhappy with it:

>>> def chunker(seq, size):
...     return (tuple(seq[pos:pos+size]) for pos in xrange(0, len(seq), size))
...
>>> x = range(11)
>>> x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> chunker(x, 2)
<generator object <genexpr> at 0x00B44328>
>>> list(chunker(x, 2))
[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9), (10,)]
>>> list(izip(x[1::2], x[::2]))
[(1, 0), (3, 2), (5, 4), (7, 6), (9, 8)]

As you can see, this has the advantage of properly handling an uneven amount of elements, which may or not be important to you. There's also this recipe from the itertools documentation itself:

>>> def grouper(n, iterable, fillvalue=None):
...     "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
...     args = [iter(iterable)] * n
...     return izip_longest(fillvalue=fillvalue, *args)
...
>>>
>>> from itertools import izip_longest
>>> list(grouper(2, x))
[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9), (10, None)]
Paolo Bergantino
Thanks - both recipes looks good. Anyway I asked because I was interested what are the other ways to do this (and to learn more Python -- and I did :))
paffnucy
+2  A: 

Try:

def alternate(i):
    i = iter(i)
    while True:
        yield(i.next(), i.next())

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

This solution works on any sequence, not just lists, and doesn't copy the sequence (it will be far more efficient if you only want the first few elements of a long sequence).

James Hopkin
O really like this solution, thanks!
paffnucy
Argh, why I can't edit comment? Should be "I really like..."
paffnucy