Rafal
Rafal

Reputation: 93

Looking for an elegant way for looping simultaneously over two list with different lengths

I'm looking for the most elegant/short/pythonic way to iterate through two uneven lists simultaneously. If the shorter list ends at some point, it should start to iterate from the beginning.

So far, I managed to do it with the while, which I consider as ugly, and too long (from various reasons I need as short code as possible).

list1 = ["a", "b", "c"]
list2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

i1 = 0
i2 = 0
while True:
    if i2 == len(list2):
        break
    if i1 == len(list1):
        i1 = 0
    print(list1[i1], list2[i2])
    i1 += 1
    i2 += 1

The expected result should look like this. I'm achieving it with while loop (the code above). But I need to have as short code as possible:

a 1
b 2
c 3
a 4
b 5
c 6
a 7
b 8
c 9
a 10

Upvotes: 3

Views: 155

Answers (5)

Alex Yu
Alex Yu

Reputation: 3537

Use itertools:

import itertools
list1 = ["a","b","c"]
list2 = [1,2,3,4,5,6,7,8,9,10]
print(list(itertools.cycle(list1), list2))

Upvotes: 0

Mad Physicist
Mad Physicist

Reputation: 114230

If you don't know the sizes of your lists, use sorted to get it:

list1 = ["a", "b", "c"]
list2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

shorter, longer = sorted([list1, list2], key=len)

Now you can itertools.cycle the shorter one, and zip:

for item1, item2 in zip(cycle(shorter), longer):
    ...

This won't necessarily print your items in the order that you may have originally wanted (list1 on the left, list2 on the right). To fix that, you can just compute the longer list by hand:

iter1, iter2 = cycle(list1), list2 if len(list1) < len(list2) else list1, cycle(list2)
for item1, item2 in zip(iter1, iter2):
    ...

You could make it a one-liner with

for item1, item2 in zip(*(cycle(list1), list2 if len(list1) < len(list2) else list1, cycle(list2))):
    ...

Upvotes: 1

Hoog
Hoog

Reputation: 2298

I've got something that is a bit cleaner than what you've got and doesn't require you know in advance which is larger. No idea if this is the most elegant/short/pythonic way to do things but here goes:

list1 = ["a","b","c"]
list2 = [1,2,3,4,5,6,7,8,9,10]

length1 = len(list1)
length2 = len(list2)

for i in range(max(length1,length2)):
    print(list1[i%length1],list2[i%length2])

prints the following:

a 1
b 2
c 3
a 4
b 5
c 6
a 7
b 8
c 9
a 10

Upvotes: 4

Dani Mesejo
Dani Mesejo

Reputation: 61910

You could do:

list1 = ["a", "b", "c"]
list2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

for i, e in enumerate(list2):
    print(list1[i % len(list1)], e)

Output

a 1
b 2
c 3
a 4
b 5
c 6
a 7
b 8
c 9
a 10

Upvotes: 4

Jean-Fran&#231;ois Fabre
Jean-Fran&#231;ois Fabre

Reputation: 140168

zip both lists, feeding the shortest one to itertools.cycle so it repeats indefinitely (until list2 ends):

import itertools

list1 = ["a","b","c"]
list2 = [1,2,3,4,5,6,7,8,9,10]

for a,b in zip(itertools.cycle(list1),list2):
    print(a,b)

prints:

a 1
b 2
c 3
a 4
b 5
c 6
a 7
b 8
c 9
a 10

(of course don't use itertools.zip_longest as cycle never ends, which would create an infinite loop)

Upvotes: 9

Related Questions