在Python中平均分布和压缩两个不同长度的列表

时间:2018-12-20 16:26:54

标签: python list

我有两个列表:

A = ["a","b","c","d","e","f","g","h","i"]
B = [1,2,3]

A比B长3倍,因此我想使用它们将它们匹配在一起,如下所示:

C = [("a",1"),("b",1"),("c",1"),
     ("d",2),("e",2),("f",2),
     ("g",3),("h",3),("i",3)]

因此,A的前三个元素与B的第一个元素匹配,A的下三个元素与B的第二个元素匹配,依此类推。

富特莫尔,这是一个非常简单的例子。当一个列表比另一个列表大而不是整数时,我也会对如何最好地公平分配元素感兴趣。例如,我的两个列表长10001和511个元素,所以第一个比第二个大〜19.57。最好是我想使用两个列表中的每个元素。

5 个答案:

答案 0 :(得分:3)

假设A的长度是B的倍数,您可以轻松做到

>>> scale = len(A) // len(B)
>>> [(a, B[i // scale]) for i, a in enumerate(A)] 
[('a', 1),
 ('b', 1),
 ('c', 1),
 ('d', 2),
 ('e', 2),
 ('f', 2),
 ('g', 3),
 ('h', 3),
 ('i', 3)]

工作原理:

  1. 确定k的值,使len(A) == k * len(B)
  2. 遍历A,然后使用k通过将当前索引除以B来确定选择哪个值{

如果长度不是整数倍,它将抛出

IndexError: list index out of range

您可以通过计算scale来规避这一点

scale = len(A) // len(B) * len(B)

例如,

A = ["a", "b", "c", "d", "e", "f", "g", "h"]
B = [1, 2, 3]

>>> scale = len(A) // len(B) * len(B)
>>> [(a, B[i // scale]) for i, a in enumerate(A)] 
[('a', 1),
 ('b', 1),
 ('c', 1),
 ('d', 1),
 ('e', 1),
 ('f', 1),
 ('g', 2),
 ('h', 2)]

这是使用itertools repeatchain.from_iterable的功能方法。

>>> from itertools import repeat, chain
>>> list(zip(A, chain.from_iterable(zip(*repeat(B, scale)))))
[('a', 1),
 ('b', 1),
 ('c', 1),
 ('d', 2),
 ('e', 2),
 ('f', 2),
 ('g', 3),
 ('h', 3),
 ('i', 3)]

答案 1 :(得分:1)

在这里,我认为第一个列表较长。

这是简单的方法:

rep = len(A) // len(B)
ia = iter(A)
C = [(next(ia), b) for b in B for i in range(rep)]
C.extend((a, B[-1]) for a in ia)         # in case len(A) is not an exact multiple of len(B)

答案 2 :(得分:0)

您可以使用grouper文档中的itertools recipe(或从more_itertools中导入)。

食谱:

from itertools import zip_longest

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

应用程序:

>>> from more_itertools import grouper                                                               
>>> A = ["a","b","c","d","e","f","g","h","i"]                                                                          
>>> B = [1,2,3]                                                                                                        
>>> [(x, i) for vals, i in zip(grouper(A, len(B)), B) for x in vals]                                                   
[('a', 1),
 ('b', 1),
 ('c', 1),
 ('d', 2),
 ('e', 2),
 ('f', 2),
 ('g', 3),
 ('h', 3),
 ('i', 3)]

答案 3 :(得分:0)

您还可以尝试使用zip()并用自己的列表理解重复B

>>> A = ["a","b","c","d","e","f","g","h","i"]
>>> B = [1,2,3]
>>> list(zip(A, (y for x in B for y in len(B) * [x])))
[('a', 1), ('b', 1), ('c', 1), ('d', 2), ('e', 2), ('f', 2), ('g', 3), ('h', 3), ('i', 3)]

还建议不要对len(B) * 3进行硬编码,而使用scale = len(A) // len(B)来获取比例分布,如@coldspeed's答案所示

答案 4 :(得分:0)

您还可以将A分组为子列表列表,每个子列表的长度为B

A = ["a","b","c","d","e","f","g","h","i"]
B = [1,2,3]
_b = len(B)
new_a = [A[i:i+_b] for i in range(0, len(A), _b)]
final_result = [(c, i) for a, i in zip(new_a, B) for c in a]

输出:

[('a', 1), ('b', 1), ('c', 1), ('d', 2), ('e', 2), ('f', 2), ('g', 3), ('h', 3), ('i', 3)]