Create a dictionary by zipping together two lists of uneven length

Question:

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'}
Asked By: Mat

||

Answers:

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)
Answered By: Dani Mesejo

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'}
Answered By: cs95

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

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

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.

Answered By: RoadRunner

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'}
Answered By: iGian
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.