Is There a Better Way to Iterate Over Two Lists, Getting One Element from Each List for Each Iteration

How do I iterate through two lists in parallel?

Python 3

for f, b in zip(foo, bar):
print(f, b)

zip stops when the shorter of foo or bar stops.

In Python 3, zip
returns an iterator of tuples, like itertools.izip in Python2. To get a list
of tuples, use list(zip(foo, bar)). And to zip until both iterators are
exhausted, you would use
itertools.zip_longest.

Python 2

In Python 2, zip
returns a list of tuples. This is fine when foo and bar are not massive. If they are both massive then forming zip(foo,bar) is an unnecessarily massive
temporary variable, and should be replaced by itertools.izip or
itertools.izip_longest, which returns an iterator instead of a list.

import itertools
for f,b in itertools.izip(foo,bar):
print(f,b)
for f,b in itertools.izip_longest(foo,bar):
print(f,b)

izip stops when either foo or bar is exhausted.
izip_longest stops when both foo and bar are exhausted.
When the shorter iterator(s) are exhausted, izip_longest yields a tuple with None in the position corresponding to that iterator. You can also set a different fillvalue besides None if you wish. See here for the full story.


Note also that zip and its zip-like brethen can accept an arbitrary number of iterables as arguments. For example,

for num, cheese, color in zip([1,2,3], ['manchego', 'stilton', 'brie'], 
['red', 'blue', 'green']):
print('{} {} {}'.format(num, color, cheese))

prints

1 red manchego
2 blue stilton
3 green brie

Is there a better way to iterate over two lists, getting one element from each list for each iteration?

This is as pythonic as you can get:

for lat, long in zip(Latitudes, Longitudes):
print(lat, long)

Iterating over two lists one after another

This can be done with itertools.chain:

import itertools

l1 = [1, 2, 3, 4]
l2 = [5, 6, 7, 8]

for i in itertools.chain(l1, l2):
print(i, end=" ")

Which will print:

1 2 3 4 5 6 7 8 

As per the documentation, chain does the following:

Make an iterator that returns elements from the first iterable until it is exhausted, then proceeds to the next iterable, until all of the iterables are exhausted.

If you have your lists in a list, itertools.chain.from_iterable is available:

l = [l1, l2]
for i in itertools.chain.from_iterable(l):
print(i, end=" ")

Which yields the same result.

If you don't want to import a module for this, writing a function for it is pretty straight-forward:

def custom_chain(*it):
for iterab in it:
yield from iterab

This requires Python 3, for Python 2, just yield them back using a loop:

def custom_chain(*it):
for iterab in it:
for val in iterab:
yield val

In addition to the previous, Python 3.5 with its extended unpacking generalizations, also allows unpacking in the list literal:

for i in [*l1, *l2]:
print(i, end=" ")

though this is slightly faster than l1 + l2 it still constructs a list which is then tossed; only go for it as a final solution.

Efficient way to iterate over two related ArrayLists?

The Answer by dreamcrash is correct: While your looping of a pair of arrays works, you should instead take advantage of Java as a OOP language by defining your own class.

Record

Defining such a class is even simpler in Java 16 with the new records feature. Write your class as a record when it’s main purpose is communicating data, transparently and immutably.

A record is very brief by default. The compiler implicitly creates the constructor, getters, equals & hashCode, and toString. You need only declare the type and name of each member field.

record ColorNoun ( String color , String noun ) {}

Use a record like a conventional class. Instantiate with new.

ColorNoun blueSky = new ColorNoun ( "Blue" , "Sky" ) ;

Note that a record can be declared locally within a method, or declared separately like a conventional class.

Iterate through three lists multiple times sequentially picking one element from a list in each iteration

You can iterate as such for the solution:

subjects=["Americans","Indians"] 
verbs=["plays","watch"]
objects=["Baseball","cricket"]

for s in subjects:
for v in verbs:
for o in objects:
print(s,v,o+".")

Iterating over every two elements in a list

You need a pairwise() (or grouped()) implementation.

def pairwise(iterable):
"s -> (s0, s1), (s2, s3), (s4, s5), ..."
a = iter(iterable)
return zip(a, a)

for x, y in pairwise(l):
print("%d + %d = %d" % (x, y, x + y))

Or, more generally:

def grouped(iterable, n):
"s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), (s2n,s2n+1,s2n+2,...s3n-1), ..."
return zip(*[iter(iterable)]*n)

for x, y in grouped(l, 2):
print("%d + %d = %d" % (x, y, x + y))

In Python 2, you should import izip as a replacement for Python 3's built-in zip() function.

All credit to martineau for his answer to my question, I have found this to be very efficient as it only iterates once over the list and does not create any unnecessary lists in the process.

N.B: This should not be confused with the pairwise recipe in Python's own itertools documentation, which yields s -> (s0, s1), (s1, s2), (s2, s3), ..., as pointed out by @lazyr in the comments.

Little addition for those who would like to do type checking with mypy on Python 3:

from typing import Iterable, Tuple, TypeVar

T = TypeVar("T")

def grouped(iterable: Iterable[T], n=2) -> Iterable[Tuple[T, ...]]:
"""s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), ..."""
return zip(*[iter(iterable)] * n)

Iterating over multiple lists simultaneously in Python

You can use zip and itertools.chain like this:

from itertools import chain

first = [0, 1, 2, 3, 1, 5, 6, 7, 1, 2, 3, 5, 1, 1, 2, 3, 5, 6]
second = [
[(13, 12, 32), (11, 444, 25)],
[(312, 443, 12), (123, 4, 123)],
[(545, 541, 1), (561, 112, 560)]
]
zip(first, chain(*(chain(*second))))

UPDATE

def add(x, y):
return x + y

# Flatten the second list
second_flattened = list(chain(*(chain(*second))))

# There is probably a better way to achieve this
foo = [add(x, y) for x, y in zip(first, second_flattened)]

# If second is longer we should append unprocessed values
if len(second_flattened) > len(first):
foo += second_flattened[len(foo): ]

bar = [foo[i:i+3] for i in range(0, len(foo), 3)]
second = [bar[i:i+2] for i in range(0, len(foo) / 3, 2)]

How to iterate through list infinitely with +1 offset each loop

You can use a deque which has a built-in and efficient rotate function (~O(1)):

>>> d = deque([0,1,2])
>>> for _ in range(10):
... print(*d)
... d.rotate(-1) # negative -> rotate to the left
...
0 1 2
1 2 0
2 0 1
0 1 2
1 2 0
2 0 1
0 1 2
1 2 0
2 0 1
0 1 2

What is the best way to iterate over multiple lists at once?

The usual way is to use zip():

for x, y in zip(a, b):
# x is from a, y is from b

This will stop when the shorter of the two iterables a and b is exhausted. Also worth noting: itertools.izip() (Python 2 only) and itertools.izip_longest() (itertools.zip_longest() in Python 3).



Related Topics



Leave a reply



Submit