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'}
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)
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'}
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'}
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'}
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)
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'}
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'}