Create a dictionary by zipping together two lists of uneven length

Viewed 3369

I have two lists different lengths, L1 and L2. L1 is longer than L2. I would like to get a dictionary with members of L1 as keys and members of L2 as values.

As soon as all the members of L2 are used up. I would like to start over and begin again with L2[0].

L1 = ['A', 'B', 'C', 'D', 'E']    
L2 = ['1', '2', '3']    
D = dict(zip(L1, L2))    
print(D)

As expected, the output is this:

{'A': '1', 'B': '2', 'C': '3'}

What I would like to achieve is the following:

{'A': '1', 'B': '2', 'C': '3', 'D': '1', 'E': '2'}
5 Answers

Use itertools.cycle to cycle around to the beginning of L2:

from itertools import cycle
dict(zip(L1, cycle(L2)))
# {'A': '1', 'B': '2', 'C': '3', 'D': '1', 'E': '2'}

In your case, concatenating L2 with itself also works.

# dict(zip(L1, L2 * 2))
dict(zip(L1, L2 + L2))
# {'A': '1', 'B': '2', 'C': '3', 'D': '1', 'E': '2'}

Use itertools.cycle:

from itertools import cycle

L1 = ['A', 'B', 'C', 'D', 'E']
L2 = ['1', '2', '3']

result = dict(zip(L1, cycle(L2)))

print(result)

Output

{'E': '2', 'B': '2', 'A': '1', 'D': '1', 'C': '3'}

As an alternative you could use enumerate and index L2 modulo the length of L2:

result = {v: L2[i % len(L2)] for i, v in enumerate(L1)}
print(result)

cycle is fine, but I shall add this modulo based approach:

{x: L2[i % len(L2)] for i, x in enumerate(L1)]}

You can also use a collections.deque() to create an circular FIFO queue:

from collections import deque

L1 = ['A', 'B', 'C', 'D', 'E']    
L2 = deque(['1', '2', '3'])

result = {}
for letter in L1:
    number = L2.popleft()
    result[letter] = number
    L2.append(number)

print(result)
# {'A': '1', 'B': '2', 'C': '3', 'D': '1', 'E': '2'}

Which pops the left most item currently in L2 and appends it to the end once the number is added to the dictionary.

Note: Both collections.deque.popleft() and collections.deque.append() are O(1) operations, so the above is still O(N), since you need to traverse all the elements in L1.

Other option without dependencies with good old for loop:

D = {}
for i, e in enumerate(L1):
  D[e] = L2[i%len(L2)]

D #=> {'A': '1', 'B': '2', 'C': '3', 'D': '1', 'E': '2'}

Or just:

{ e: L2[i%len(L2)] for i, e in enumerate(L1) }
#=> {'A': '1', 'B': '2', 'C': '3', 'D': '1', 'E': '2'}
Related