无需 Itertools 从两个列表生成唯一对

Generate Unique Pairs From Two Lists Without Itertools

我在一个列表上循环了两次,想要捕获所有唯一的对,而不是所有的组合——即。成对的顺序无关紧要

listy=[0,1,2]
out=[]
for i in listy:
   for j in listy:
      out.append([i,j])

我得到的输出是 [[0,0],[0,1],[0,2],[1,0],[1,1],[1,2],[ 2,0],[2,1],[2,2]]

我要找的是[[0,0],[0,1],[0,2],[1,1],[1,2],[2,2]]

一个可能的解决方案是,

listy=[0,1,2]
out=[]
for i in listy:
   for j in listy:
      pair=set([i,j])
      if pair not in out:
          out.append(pair)

这会产生 [{0},{0,1},{0,2},{1},{1,2},{2}]

然而,这会导致繁重的脚本(列表很长)效率低下,而且我也不想要集合列表。我想要一个列表列表。

有没有更好的方法在不使用 itertools 的情况下实现这一点(我想要一个实现,我也可以应用到 javascript 而无需太多反思)

选项 1 -“小修复”

一个简单的“修复”是:

listy=[0,1,2]
out=set()
for i in listy:
    for j in listy:
        if (i, j) not in out and (j, i) not in out:
            out.add((i,j))

结果是:

{(0, 1), (1, 2), (0, 0), (1, 1), (0, 2), (2, 2)}

然而,这不是一个有效的实现,因为我们必须检查两次是否一个元素在列表中。

选项 2 - 更有效的实施

您可以使用简单的数组扫描来实现您的目标:

listy=[0,1,2]
out = [(i, j) for i in range(len(listy)) for j in range(i, len(listy))]

注意:我使用元组来表示对,您可以使用以下方法轻松地将其更改为列表列表:

out = [[i, j] for i in range(len(listy)) for j in range(i, len(listy))]

我根本不知道 javascript,但如果有类似于列表理解的东西,我会试试这个:

listy = [0,1,2]
pairs = [[i, j] for i in listy for j in listy if i <= j]

对的内容完全如你所愿:

[[0, 0], [0, 1], [0, 2], [1, 1], [1, 2], [2, 2]]

直接从输入 list 生成您想要的结果的 itertools.combinations_with_replacement(listy, 2) 最直接的翻译(匹配您想要的行为)是:

listy = [0,1,2]
out = []
for idx, i in enumerate(listy):
   for j in listy[idx:]:
      out.append([i, j])

唯一的变化是使用 enumerate(在迭代时获取正在迭代的当前索引)并切片内部循环中使用的 listy(因此它从与外循环的当前运行)。

这会以最小的开销获得请求的准确结果(它确实对 list 进行了大小递减的浅拷贝,每个内循环一次,但这在 Python 中相当快;除非 list 很大,否则它应该是一个非常小的成本)。如果你需要避免切片,你可以使内部循环成为一个带索引的 index-based 循环(但实际上,索引的开销足够高,它经常会输给切片):

listy = [0,1,2]
out = []
for idx, i in enumerate(listy):
   for idxj in range(idx, len(listy)):
      out.append([i, j[idxj]])