简体   繁体   中英

Pythonic way to iterate over a shifted list of tuples

Given a list L = [('a',3),('b',4),('c',14),('d',10)] , the desired output is the first item from a tuple and the second item from the next tuple, eg:

a 4
b 14
c 10

Straightforward but unpythonic way would be

for i in range(len(L)-1):
    print(L[i][0], L[i+1][1])


Alternatively, this is what I've came up with:

for (a0,a1),(b0,b1) in zip(L,L[1:]):
    print(a0,b1)

but it seems to be wasteful. Is there a standard way to do this?

I personally think both options are just fine It is possible to extract the items and join them:

pairs = zip(map(itemgetter(0), L), map(itemgetter(1), L[1:]))
# [('a', 4), ('b', 14), ('c', 10)]

A pythonic way is to use a generator expression.

You could write it like this:

for newTuple in ((L[i][0], L[i+1][1]) for i in range(len(L)-1)):
  print(newTuple)

It looks like a list-comprehension, but the iterator-generator will not create the full list, just yields a tuple by tuple, so it is not taking additional memory for a full-copy of list.

To improve your zip example (which is already good), you could use itertools.islice to avoid creating a sliced copy of the initial list. In python 3, the below code only generates values, no temporary list is created in the process.

import itertools

L = [('a',3),('b',4),('c',14),('d',10)]


for (a0,_),(_,b1) in zip(L,itertools.islice(L,1,None)):
    print(a0,b1)

I'd split the first and second items with the help of two generator expressions, use islice to drop one item and zip the two streams together again.

first_items = (a for a, _ in L)
second_items = (b for _, b in L)
result = zip(first_items, islice(second_items, 1, None))

print(list(result))
# [('a', 4), ('b', 14), ('c', 10)]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM