简体   繁体   English

在没有 Itertools 的情况下从两个列表生成唯一的对

[英]Generate Unique Pairs From Two Lists Without Itertools

I am looping over a list twice and want to catch all unique pairs, rather than all combinations- ie.我在一个列表上循环了两次,想要捕获所有唯一的对,而不是所有的组合——即。 order in the pair doesn't matter对中的顺序无关紧要

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

The output I'm getting is [[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,0],[1,1],[1,2],[2,0], [2,1],[2,2]]

What I am looking for is [[0,0],[0,1],[0,2],[1,1],[1,2],[2,2]]我正在寻找的是 [[0,0],[0,1],[0,2],[1,1],[1,2],[2,2]]

One possible solution is,一种可能的解决方案是,

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)

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

However this creates inefficiency in what is a heavy script (the lists are long) and I also do not want a list of sets.但是,这会在繁重的脚本中造成效率低下(列表很长),而且我也不想要集合列表。 I want a list of lists.我想要一个列表列表。

Is there a better way to achieve this without using itertools (I want an implementation I can also apply to javascript without too much rethinking)有没有更好的方法可以在不使用 itertools 的情况下实现这一点(我想要一个实现,我也可以应用到 javascript 而无需太多重新思考)

Option 1 - "minor fix"选项 1 - “小修复”

A trivial "fix" would be:一个微不足道的“修复”将是:

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

The result is:结果是:

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

However this is not an efficient implementation, because we have to check twice if an element is in the list.然而,这不是一个有效的实现,因为我们必须检查两次元素是否在列表中。

Option 2 - More efficient implementation选项 2 - 更有效的实施

You could achieve your goal using a trivial scan of the array:您可以使用数组的简单扫描来实现您的目标:

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

NOTE: I use tuples for the pairs, you could easily change that into a list of lists using:注意:我对对使用元组,您可以使用以下方法轻松地将其更改为列表列表:

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

I don't know javascript at all, but if there is something analogous to list comprehension I would try this:我根本不懂javascript,但如果有类似于列表理解的东西,我会试试这个:

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

The content of pairs is exactly as you wanted:对的内容完全符合您的要求:

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

The most straightforward translation of itertools.combinations_with_replacement(listy, 2) (which matches the behavior you desire) that directly generates the results you want from an input list is:直接从输入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])

Only change is the use of enumerate (to get the current index being iterated as you iterate) and slicing the listy used in the inner loop (so it starts at the same index as the current run of the outer loop).唯一的变化是使用enumerate (在迭代时获取当前索引)并切片内部循环中使用的listy (因此它从与外部循环的当前运行相同的索引开始)。

This gets the exact result requested with minimal overhead (it does make shallow copies of the list , of decreasing size, once for each inner loop, but this is fairly quick in Python; unless the list is huge, it should be a pretty minimal cost).这以最小的开销获得了所请求的确切结果(它确实为每个内部循环制作了list的浅表副本,大小减小了一次,但这在 Python 中相当快;除非list很大,否则它应该是一个非常小的成本)。 If you need to avoid slicing, you can make the inner loop an index-based loop with indexing (but in practice, the overhead of indexing is high enough that it'll often lose to the slicing):如果您需要避免切片,您可以使内部循环成为带有索引的基于索引的循环(但在实践中,索引的开销足够高,以至于它经常会输给切片):

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

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

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