简体   繁体   English

如何 zip 两个不同大小的列表,重复较短的列表?

[英]How to zip two differently sized lists, repeating the shorter list?

I want to zip two list with different length我想要 zip 两个长度不同的列表

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.但是内置的zip不会重复与更大的列表配对。 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 :您可以使用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 .只需确保较大的列表在A

You can use itertools.cycle :您可以使用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']]

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.我希望没关系。

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)

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尝试计算并舍入第一个列表长度的一半,如果它是浮点数,则也加1
  • Iterate using zip() before that multiply second YesNo list with the calculated number before在将第二个 YesNo 列表与之前计算的数字相乘之前使用zip()进行迭代

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 ).请注意,这里不需要仔细计算乘数,因为zip只会到达最短列表的长度(乘数的重点是确保最短列表是my_list )。 That is, the result would be the same if 100 were used instead of 3 .也就是说,如果使用100而不是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) 2可以替换为len(another_list)

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)))]

Let's use np.tile and zip :让我们使用np.tilezip

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

I like Henry Yik's answer and it's a bit faster to execute, but here is an answer without using itertools.我喜欢Henry Yik 的答案,而且执行速度要快一些,但这是一个不使用 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']]

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)

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

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这可以使用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)]

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或者如果A的元素不是连续的并且不担心列表长度

[(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)]
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 zip 目录字典

{'one': 1, 'two': 2, 'three': 3}

Note: Python 3.7+注意:Python 3.7+

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM