Não é mais possível fazer postagens ou usar assinaturas novas da Usenet nos Grupos do Google. O conteúdo histórico continua disponível.
Dismiss

iterating "by twos"

22 visualizações
Pular para a primeira mensagem não lida

kj

não lida,
29 de jul. de 2008, 13:36:1129/07/2008
para


Is there a special pythonic idiom for iterating over a list (or
tuple) two elements at a time?

I mean, other than

for i in range(0, len(a), 2):
frobnicate(a[i], a[i+1])

?

I think I once saw something like

for (x, y) in forgotten_expression_using(a):
frobnicate(x, y)

Or maybe I just dreamt it! :)

Thanks!
--
NOTE: In my address everything before the first period is backwards;
and the last period, and everything after it, should be discarded.

George Trojan

não lida,
29 de jul. de 2008, 13:58:0529/07/2008
para
kj wrote:
> Is there a special pythonic idiom for iterating over a list (or
> tuple) two elements at a time?
>
> I mean, other than
>
> for i in range(0, len(a), 2):
> frobnicate(a[i], a[i+1])
>
> ?
>
> I think I once saw something like
>
> for (x, y) in forgotten_expression_using(a):
> frobnicate(x, y)
>
> Or maybe I just dreamt it! :)
>
> Thanks!
I saw the same thing, forgot where though. But I put it in my library.
Here it is:

# x.py
import itertools

def pairs(seq):
is1 = itertools.islice(iter(seq), 0, None, 2)
is2 = itertools.islice(iter(seq), 1, None, 2)
return itertools.izip(is1, is2)

s = range(9)
for x, y in pairs(s):
print x, y

dilbert@trojan> python x.py
0 1
2 3
4 5
6 7

bearoph...@lycos.com

não lida,
29 de jul. de 2008, 14:04:1329/07/2008
para
Something like this may be fast enough:

>>> from itertools import izip
>>> xpartition = lambda seq, n=2: izip(*(iter(seq),) * n)
>>> xprimes = (x for x in xrange(2, 100) if all(x % i for i in xrange(2, x)))
>>> list(xpartition(xprimes))
[(2, 3), (5, 7), (11, 13), (17, 19), (23, 29), (31, 37), (41, 43),
(47, 53), (59, 61), (67, 71), (73, 79), (83, 89)]

Bye,
bearophile

gil...@gmail.com

não lida,
29 de jul. de 2008, 14:36:2029/07/2008
para
On Jul 29, 1:36 pm, kj <so...@987jk.com.invalid> wrote:
> Is there a special pythonic idiom for iterating over a list (or
> tuple) two elements at a time?

I use this one a lot:

for x, y in zip(a, a[1:]):
frob(x, y)

Geoff G-T

william tanksley

não lida,
29 de jul. de 2008, 15:42:0729/07/2008
para
kj <so...@987jk.com.invalid> wrote:
> Is there a special pythonic idiom for iterating over a list (or
> tuple) two elements at a time?

I don't know of one, and I shouldn't be answering, but the following
should work:

def gulp_two(items):
for i,j in zip(items[0::2], items[1::2]):
yield (i,j)

Let's see...
>>> list(gulp_two(range(10)))
[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]

Okay, it works.

-Wm

gil...@gmail.com

não lida,
29 de jul. de 2008, 15:42:1929/07/2008
para

Whoops, I misread the original post. That would be:

for x, y in zip(a[::2], a[1::2]):
frob(x, y)

... which I don't use a lot.

>>> a = range(9)


>>> for x, y in zip(a, a[1:]):

... print x, y
...
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
>>> for x, y in zip(a[::2], a[1::2]):
... print x, y
...


0 1
2 3
4 5
6 7

Geoff G-T

Erik Max Francis

não lida,
29 de jul. de 2008, 16:11:5729/07/2008
para
gil...@gmail.com wrote:

It doesn't work:

>>> a = range(10)
>>> [(x, y) for x, y in zip(a, a[1:])]
[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9)]

What you meant was this:

>>> [(x, y) for x, y in zip(a[::2], a[1::2])]


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

but this creates three sublists through slicing and zip. The use of
islice and izip is better, particularly if the list that's being
iterated over is large.

--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM, Y!M erikmaxfrancis
Tell me the truth / I'll take it like a man
-- Chante Moore

Erik Max Francis

não lida,
29 de jul. de 2008, 16:12:4829/07/2008
para
gil...@gmail.com wrote:

> Whoops, I misread the original post. That would be:
>
> for x, y in zip(a[::2], a[1::2]):
> frob(x, y)
>
> ... which I don't use a lot.

Sorry, posted before I saw your reply. Still, you're building three
sublists in order to just iterate over them.

kj

não lida,
29 de jul. de 2008, 16:22:1629/07/2008
para

Thanks for all the replies. I learned a lot!

kynn

Terry Reedy

não lida,
29 de jul. de 2008, 16:38:5329/07/2008
para pytho...@python.org

kj wrote:

> Is there a special pythonic idiom for iterating over a list (or
> tuple) two elements at a time?
>
> I mean, other than
>
> for i in range(0, len(a), 2):
> frobnicate(a[i], a[i+1])

There have been requests to add a grouper function to itertools, but its
author has resisted because there are at least three things one might do
with the short remainder group left over when the group size does not
evenly divide the sequence size: drop it, return it, or fill it to the
requested groupsize with a dummy value and then return it. Here is a
version of the first alternative.

def grouper(iterable,n):
'''Return items from iterable in groups of n.
This version drops incomplete groups.
Python 3.0'''

it=iter(iterable)
ranger = range(n)
while True:
ret = []
for i in ranger:
ret.append(next(it))
yield ret

for pair in grouper(range(11),2):
print(pair)

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

kj

não lida,
29 de jul. de 2008, 17:37:4329/07/2008
para

>kj wrote:

>> Is there a special pythonic idiom for iterating over a list (or
>> tuple) two elements at a time?
>>
>> I mean, other than
>>
>> for i in range(0, len(a), 2):
>> frobnicate(a[i], a[i+1])

>There have been requests to add a grouper function to itertools, but its
>author has resisted because there are at least three things one might do
>with the short remainder group left over when the group size does not
>evenly divide the sequence size: drop it, return it, or fill it to the
>requested groupsize with a dummy value and then return it.

Why not make this choice a third argument to the grouper function?

Kynn

Daniel da Silva

não lida,
30 de jul. de 2008, 01:08:2630/07/2008
para pytho...@python.org
The following method is similar to the others provided, but yields an
index value as well (similar to the enumerate(iterable) function).
This is useful in some (but not all) situations.

If the iterable object's iterator returns an even number of items then
you're fine; otherwise it will throw away the last item because it
doesn't have a full pair to return.

-------------------------
import itertools

def enumeratePairs(x):
it = iter(x)

for i in itertools.count():
p = it.next()
q = it.next()
yield i, (p,q)

raise StopIteration
--------------------------
>>> for v in enumeratePairs("hello i am daniel"):
... print v
...
(0, ('h', 'e'))
(1, ('l', 'l'))
(2, ('o', ' '))
(3, ('i', ' '))
(4, ('a', 'm'))
(5, (' ', 'd'))
(6, ('a', 'n'))
(7, ('i', 'e'))
-------------------------------

> --
> http://mail.python.org/mailman/listinfo/python-list
>

gil...@gmail.com

não lida,
30 de jul. de 2008, 10:00:2730/07/2008
para
On Jul 29, 4:11 pm, Erik Max Francis <m...@alcyone.com> wrote:

> gil...@gmail.com wrote:
> > for x, y in zip(a, a[1:]):
> >     frob(x, y)
>
> What you meant was this:
>
>  >>> [(x, y) for x, y in zip(a[::2], a[1::2])]
> [(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]
>
> but this creates three sublists through slicing and zip.  The use of
> islice and izip is better, particularly if the list that's being
> iterated over is large.

The lists I use it with are generally pretty small (a few
thousand items at most) so I decided to go with simple rather than
clever. That said, I use it enough that it should become its own
function, at which point I'll probably grab something from this
thread.

Cheers,
Geoff G-T

shahm...@gmail.com

não lida,
7 de ago. de 2008, 11:06:1207/08/2008
para

This avoids unnecessary copies of the slice approaches, it does,
however, not include the tail values if the length of iterable isn't
evenly divisible by 'size'.

def groups(iterable, size=2):
return itertools.izip(*[iter(iterable)]*size)

print list(groups(xrange(5)))

[(0, 1), (1, 2), (3, 4)]

--Shahms

castironpi

não lida,
7 de ago. de 2008, 14:05:0307/08/2008
para
On Jul 29, 3:38 pm, Terry Reedy <tjre...@udel.edu> wrote:
> kj wrote:
> > Is there a special pythonic idiom for iterating over a list (or
> > tuple) two elements at a time?
>
> > I mean, other than
>
> > for i in range(0, len(a), 2):
> >     frobnicate(a[i], a[i+1])
>
> There have been requests to add a grouper function to itertools, but its
> author has resisted because there are at least three things one might do
> with the short remainder group left over when the group size does not
> evenly divide the sequence size: drop it, return it, or fill it to the
> requested groupsize with a dummy value and then return it.

We note that three distinct methods of the mapping type protocol
support default, -or this if not found-, argument passing.

a.get(k[, x]) a[k] if k in a, else x (4)
a.setdefault(k[, x]) a[k] if k in a, else x (also setting it) (5)
a.pop(k[, x]) a[k] if k in a, else x (and remove k) (8)

You can knock off two of them with a default value:

itertools.igroup( iterable, groupsize[, dummy] )

Observe this overlap from the string type.

find( sub[, start[, end]])
Return the lowest index in the string where substring sub is
found, ...
-1 if sub is not found.
index( sub[, start[, end]])
Like find(), but raise ValueError when the substring is not
found.

Include two grouper functions, one that drops (or fills if 'dummy'
provided), one that returns (or fills if 'dummy' provided).

Or, include two grouper functions, one that drops (or fills), one that
raises ValueError exception, including the partial group as an
attribute of the exception.

If filling with 'None' is your concern, just use a special flag:

_special= object( )
iterb= itertools.grouper( itera, 2, _special )

0 nova mensagem