32

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'}
cs95
  • 379,657
  • 97
  • 704
  • 746
Mat
  • 515
  • 5
  • 10
  • 2
    Curious as to the reason for the close votes. What about this question is too broad? If it is because the OP hasn't offered any solution, then I can understand OP may not have the first clue where to begin. Based on their explanation of the question, it does not seem like they could have googled for "cycle", "circular", or other similar keywords that would have led to a solution. – cs95 Jan 09 '19 at 09:14

5 Answers5

37

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'}
cs95
  • 379,657
  • 97
  • 704
  • 746
25

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)
Dani Mesejo
  • 61,499
  • 6
  • 49
  • 76
16

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

{x: L2[i % len(L2)] for i, x in enumerate(L1)]}
user2390182
  • 72,016
  • 6
  • 67
  • 89
8

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.

RoadRunner
  • 25,803
  • 6
  • 42
  • 75
7

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'}
iGian
  • 11,023
  • 3
  • 21
  • 36
  • Isn't that already here? https://stackoverflow.com/a/54095907/4909087 and also in another answer. – cs95 Jan 09 '19 at 09:53