How to zip two differently sized lists, repeating the shorter list?
Question:
I want to zip two list with different length
for example
A = [1,2,3,4,5,6,7,8,9]
B = ["A","B","C"]
and I expect this
[(1, 'A'), (2, 'B'), (3, 'C'), (4, 'A'), (5, 'B'), (6, 'C'), (7, 'A'), (8, 'B'), (9, 'C')]
But the built-in zip
won’t repeat to pair with the list with larger size.
Does there exist any built-in way can achieve this?
Here is my code:
idx = 0
zip_list = []
for value in larger:
zip_list.append((value,smaller[idx]))
idx += 1
if idx == len(smaller):
idx = 0
Answers:
You can use itertools.cycle
:
Make an iterator returning elements from the iterable and saving a copy of each. When the iterable is exhausted, return elements from the saved copy. Repeats indefinitely.
Example:
A = [1,2,3,4,5,6,7,8,9]
B = ["A","B","C"]
from itertools import cycle
zip_list = zip(A, cycle(B)) if len(A) > len(B) else zip(cycle(A), B)
Try this.
A = [1,2,3,4,5,6,7,8,9]
B = ["A","B","C"]
Z = []
for i, a in enumerate(A):
Z.append((a, B[i % len(B)]))
Just make sure that the larger list is in A
.
There is probably a better way, but you could make a function that repeats your list to whatever length you want.
def repeatlist(l,i):
'''give a list and a total length'''
while len(l) < i:
l += l
while len(l) > i:
l.pop()
Then do
repeatlist(B,len(A))
zip_list = zip(A,B)
symmetric, no conditionals one liner
[*zip(A*(len(B)//len(A) + 1), B*(len(A)//len(B) + 1))]
which strictly answers ‘How to zip two differently sized lists?’
needs a patch for equal sized lists to be general:
[*(zip(A, B) if len(A) == len(B)
else zip(A*(len(B)//len(A) + 1),
B*(len(A)//len(B) + 1)))]
And nowadays with list comprehentions
[(i, B[i % 3 - 1]) for i in A]
Or if the elements of A
are not sequential and not worrying about list lengths
[(j, B[i % len(B)]) for i, j in enumerate(A)] if len(A) >= len(B) else
[(A[i % len(A)], j) for i, j in enumerate(B)]
For a version that works with any finite number of potentially infinite iterables in any order:
from itertools import cycle, tee, zip_longest
def cyclical_zip(*iterables):
iterables_1, iterables_2 = zip(*map(tee, iterables)) # Allow proper iteration of iterators
for _, x in zip(
zip_longest(*iterables_1), # Limit by the length of the longest iterable
zip(*map(cycle, iterables_2))): # the cycling
yield x
assert list(cyclical_zip([1, 2, 3], 'abcd', 'xy')) == [(1, 'a', 'x'), (2, 'b', 'y'), (3, 'c', 'x'), (1, 'd', 'y')] # An example and test case
Solution for an arbitrary number of iterables, and you don’t know which one is longest (also allowing a default for any empty iterables):
from itertools import cycle, zip_longest
def zip_cycle(*iterables, empty_default=None):
cycles = [cycle(i) for i in iterables]
for _ in zip_longest(*iterables):
yield tuple(next(i, empty_default) for i in cycles)
for i in zip_cycle(range(2), range(5), ['a', 'b', 'c'], []):
print(i)
Outputs:
(0, 0, 'a', None)
(1, 1, 'b', None)
(0, 2, 'c', None)
(1, 3, 'a', None)
(0, 4, 'b', None)
d1=['one','two','three']
d2=[1,2,3,4,5]
Zip
zip(d1,d2)
<zip object at 0x05E494B8>
list of zip
list(zip(d1,d2))
dictionary of list of zip
{'one': 1, 'two': 2, 'three': 3}
Note: Python 3.7+
You can use itertools.cycle
:
from itertools import cycle
my_list = [1, 2, 3, 5, 5, 9]
another_list = ['Yes', 'No']
cyc = cycle(another_list)
print([[i, next(cyc)] for i in my_list])
# [[1, 'Yes'], [2, 'No'], [3, 'Yes'], [5, 'No'], [5, 'Yes'], [9, 'No']]
Try like this:
my_list=[ 1, 2, 3, 5, 5, 9]
another_list=['Yes','No']
if type(len(my_list)/2) == float:
ml=int(len(my_list)/2)+1
else:
ml=int(len(my_list)/2)
print([[x,y] for x,y in zip(my_list,another_list*ml)])
Native way:
- Try to calculate and round the half of the length of first list, if it is float then add 1 too
- Iterate using
zip()
before that multiply second YesNo list with the calculated number before
Let’s use np.tile
and zip
:
my_list = [1, 2, 3, 5, 5, 9]
another_list = ['Yes', 'No']
list(zip(my_list,np.tile(another_list, len(my_list)//len(another_list) + 1)) )
Output:
[(1, 'Yes'), (2, 'No'), (3, 'Yes'), (5, 'No'), (5, 'Yes'), (9, 'No')]
Do you know that the second list is shorter?
import itertools
list(zip(my_list, itertools.cycle(another_list)))
This will actually give you a list of tuples rather than a list of lists. I hope that’s okay.
A very simple approach is to multiply the short list so it’s longer:
my_list = [1, 2, 3, 5, 5, 9]
another_list = ['Yes', 'No']
zip(my_list, another_list*3))
#[(1, 'Yes'), (2, 'No'), (3, 'Yes'), (5, 'No'), (5, 'Yes'), (9, 'No')]
Note here that the multiplier doesn’t need to be carefully calculated since zip
only goes out to the length of the shortest list (and the point of the multiplier is to make sure the shortest list is my_list
). That is, the result would be the same if 100
were used instead of 3
.
You can use the modulo %
operator in a loop that counts up
my_list=[1, 2, 3, 5, 5, 9]
another_list=['Yes','No']
new_list = []
for cur in range(len(my_list)):
new_list.append([my_list[cur], another_list[cur % 2]])
# [[1, 'Yes'], [2, 'No'], [3, 'Yes'], [5, 'No'], [5, 'Yes'], [9, 'No']]
2
can be replaced with len(another_list)
I like Henry Yik’s answer and it’s a bit faster to execute, but here is an answer without using itertools.
my_list = [1, 2, 3, 5, 5, 9]
another_list = ['Yes', 'No']
new_list = []
for i in range(len(my_list)):
new_list.append([my_list[i], another_list[i % len(another_list)]])
new_list
[[1, 'Yes'], [2, 'No'], [3, 'Yes'], [5, 'No'], [5, 'Yes'], [9, 'No']]
This question is trying to solve a problem the wrong way.
What you are trying here is to get all possible permutations of the elements of two given lists. This can be easily achieved using itertools.product
>>> from itertools import product
>>> list(product(range(2), range(5)))
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4)]
>>> list(product(range(2), range(2)))
[(0, 0), (0, 1), (1, 0), (1, 1)]
>>> list(product(range(2), range(2), range(3)))
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 1, 2), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 1, 0), (1, 1, 1), (1, 1, 2)]
I want to zip two list with different length
for example
A = [1,2,3,4,5,6,7,8,9]
B = ["A","B","C"]
and I expect this
[(1, 'A'), (2, 'B'), (3, 'C'), (4, 'A'), (5, 'B'), (6, 'C'), (7, 'A'), (8, 'B'), (9, 'C')]
But the built-in zip
won’t repeat to pair with the list with larger size.
Does there exist any built-in way can achieve this?
Here is my code:
idx = 0
zip_list = []
for value in larger:
zip_list.append((value,smaller[idx]))
idx += 1
if idx == len(smaller):
idx = 0
You can use itertools.cycle
:
Make an iterator returning elements from the iterable and saving a copy of each. When the iterable is exhausted, return elements from the saved copy. Repeats indefinitely.
Example:
A = [1,2,3,4,5,6,7,8,9]
B = ["A","B","C"]
from itertools import cycle
zip_list = zip(A, cycle(B)) if len(A) > len(B) else zip(cycle(A), B)
Try this.
A = [1,2,3,4,5,6,7,8,9]
B = ["A","B","C"]
Z = []
for i, a in enumerate(A):
Z.append((a, B[i % len(B)]))
Just make sure that the larger list is in A
.
There is probably a better way, but you could make a function that repeats your list to whatever length you want.
def repeatlist(l,i):
'''give a list and a total length'''
while len(l) < i:
l += l
while len(l) > i:
l.pop()
Then do
repeatlist(B,len(A))
zip_list = zip(A,B)
symmetric, no conditionals one liner
[*zip(A*(len(B)//len(A) + 1), B*(len(A)//len(B) + 1))]
which strictly answers ‘How to zip two differently sized lists?’
needs a patch for equal sized lists to be general:
[*(zip(A, B) if len(A) == len(B)
else zip(A*(len(B)//len(A) + 1),
B*(len(A)//len(B) + 1)))]
And nowadays with list comprehentions
[(i, B[i % 3 - 1]) for i in A]
Or if the elements of A
are not sequential and not worrying about list lengths
[(j, B[i % len(B)]) for i, j in enumerate(A)] if len(A) >= len(B) else
[(A[i % len(A)], j) for i, j in enumerate(B)]
For a version that works with any finite number of potentially infinite iterables in any order:
from itertools import cycle, tee, zip_longest
def cyclical_zip(*iterables):
iterables_1, iterables_2 = zip(*map(tee, iterables)) # Allow proper iteration of iterators
for _, x in zip(
zip_longest(*iterables_1), # Limit by the length of the longest iterable
zip(*map(cycle, iterables_2))): # the cycling
yield x
assert list(cyclical_zip([1, 2, 3], 'abcd', 'xy')) == [(1, 'a', 'x'), (2, 'b', 'y'), (3, 'c', 'x'), (1, 'd', 'y')] # An example and test case
Solution for an arbitrary number of iterables, and you don’t know which one is longest (also allowing a default for any empty iterables):
from itertools import cycle, zip_longest
def zip_cycle(*iterables, empty_default=None):
cycles = [cycle(i) for i in iterables]
for _ in zip_longest(*iterables):
yield tuple(next(i, empty_default) for i in cycles)
for i in zip_cycle(range(2), range(5), ['a', 'b', 'c'], []):
print(i)
Outputs:
(0, 0, 'a', None)
(1, 1, 'b', None)
(0, 2, 'c', None)
(1, 3, 'a', None)
(0, 4, 'b', None)
d1=['one','two','three']
d2=[1,2,3,4,5]
Zip
zip(d1,d2)
<zip object at 0x05E494B8>
list of zip
list(zip(d1,d2))
dictionary of list of zip
{'one': 1, 'two': 2, 'three': 3}
Note: Python 3.7+
You can use itertools.cycle
:
from itertools import cycle
my_list = [1, 2, 3, 5, 5, 9]
another_list = ['Yes', 'No']
cyc = cycle(another_list)
print([[i, next(cyc)] for i in my_list])
# [[1, 'Yes'], [2, 'No'], [3, 'Yes'], [5, 'No'], [5, 'Yes'], [9, 'No']]
Try like this:
my_list=[ 1, 2, 3, 5, 5, 9]
another_list=['Yes','No']
if type(len(my_list)/2) == float:
ml=int(len(my_list)/2)+1
else:
ml=int(len(my_list)/2)
print([[x,y] for x,y in zip(my_list,another_list*ml)])
Native way:
- Try to calculate and round the half of the length of first list, if it is float then add 1 too
- Iterate using
zip()
before that multiply second YesNo list with the calculated number before
Let’s use np.tile
and zip
:
my_list = [1, 2, 3, 5, 5, 9]
another_list = ['Yes', 'No']
list(zip(my_list,np.tile(another_list, len(my_list)//len(another_list) + 1)) )
Output:
[(1, 'Yes'), (2, 'No'), (3, 'Yes'), (5, 'No'), (5, 'Yes'), (9, 'No')]
Do you know that the second list is shorter?
import itertools
list(zip(my_list, itertools.cycle(another_list)))
This will actually give you a list of tuples rather than a list of lists. I hope that’s okay.
A very simple approach is to multiply the short list so it’s longer:
my_list = [1, 2, 3, 5, 5, 9]
another_list = ['Yes', 'No']
zip(my_list, another_list*3))
#[(1, 'Yes'), (2, 'No'), (3, 'Yes'), (5, 'No'), (5, 'Yes'), (9, 'No')]
Note here that the multiplier doesn’t need to be carefully calculated since zip
only goes out to the length of the shortest list (and the point of the multiplier is to make sure the shortest list is my_list
). That is, the result would be the same if 100
were used instead of 3
.
You can use the modulo %
operator in a loop that counts up
my_list=[1, 2, 3, 5, 5, 9]
another_list=['Yes','No']
new_list = []
for cur in range(len(my_list)):
new_list.append([my_list[cur], another_list[cur % 2]])
# [[1, 'Yes'], [2, 'No'], [3, 'Yes'], [5, 'No'], [5, 'Yes'], [9, 'No']]
2
can be replaced with len(another_list)
I like Henry Yik’s answer and it’s a bit faster to execute, but here is an answer without using itertools.
my_list = [1, 2, 3, 5, 5, 9]
another_list = ['Yes', 'No']
new_list = []
for i in range(len(my_list)):
new_list.append([my_list[i], another_list[i % len(another_list)]])
new_list
[[1, 'Yes'], [2, 'No'], [3, 'Yes'], [5, 'No'], [5, 'Yes'], [9, 'No']]
This question is trying to solve a problem the wrong way.
What you are trying here is to get all possible permutations of the elements of two given lists. This can be easily achieved using itertools.product
>>> from itertools import product
>>> list(product(range(2), range(5)))
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4)]
>>> list(product(range(2), range(2)))
[(0, 0), (0, 1), (1, 0), (1, 1)]
>>> list(product(range(2), range(2), range(3)))
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 1, 2), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 1, 0), (1, 1, 1), (1, 1, 2)]