Python 如何仅将列表中的每个项目与其余项目进行比较?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/16603282/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to compare each item in a list with the rest, only once?
提问by Bogdanovist
Say I have an array/list of things I want to compare. In languages I am more familiar with, I would do something like
假设我有一个要比较的数组/列表。在我更熟悉的语言中,我会做类似的事情
for (int i = 0, i < mylist.size(); i++)
    for (int j = i + 1, j < mylist.size(); j++)
        compare(mylist[i], mylist[j])
This ensures we only compare each pair once. For some context, I am doing collision detection on a bunch of objects contained in the list. For each collision detected, a small 'collision' object describing the collision is appended to a list, which another routine then loops through resolving each collision (depending on the nature of the two colliding objects). Obviously, I only want to report each collision once.
这确保我们只比较每对一次。对于某些情况,我正在对列表中包含的一堆对象进行碰撞检测。对于检测到的每个碰撞,一个描述碰撞的小“碰撞”对象被附加到一个列表中,然后另一个例程循环解决每个碰撞(取决于两个碰撞对象的性质)。显然,我只想报告每个碰撞一次。
Now, what is the pythonic way of doing this, since Python favors using iterators rather than looping over indices?
现在,这样做的 Pythonic 方法是什么,因为 Python 喜欢使用迭代器而不是循环索引?
I had the following (buggy) code:
我有以下(有问题的)代码:
for this in mylist:
    for that in mylist:
        compare(this, that)
But this clearly picks up each collision twice, which lead to some strange behavior when trying to resolve them. So what is the pythonic solution here?
但这显然会导致每次碰撞两次,这会导致在尝试解决它们时出现一些奇怪的行为。那么这里的pythonic解决方案是什么?
采纳答案by poke
Of course this will generate each pair twice as each forloop will go through every item of the list.
当然,这将生成每对两次,因为每个for循环将遍历列表的每个项目。
You could use some itertoolsmagic here to generate all possible combinations:
您可以在这里使用一些itertools魔法来生成所有可能的组合:
import itertools
for a, b in itertools.combinations(mylist, 2):
    compare(a, b)
itertools.combinationswill pair each element with each other element in the iterable, but only once.
itertools.combinations将每个元素与迭代中的其他元素配对,但只配对一次。
You could still write this using index-based item access, equivalent to what you are used to, using nested forloops:
您仍然可以使用基于索引的项目访问来编写它,这与您习惯的使用嵌套for循环相同:
for i in range(len(mylist)):
    for j in range(i + 1, len(mylist)):
        compare(mylist[i], mylist[j])
Of course this may not look as nice and pythonic but sometimes this is still the easiest and most comprehensible solution, so you should not shy away from solving problems like that.
当然,这可能看起来不那么好和 Pythonic 但有时这仍然是最简单和最容易理解的解决方案,所以你不应该回避解决这样的问题。
回答by shx2
Use itertools.combinations(mylist, 2)
用 itertools.combinations(mylist, 2)
mylist = range(5)
for x,y in itertools.combinations(mylist, 2):
    print x,y
0 1
0 2
0 3
0 4
1 2
1 3
1 4
2 3
2 4
3 4
回答by Osama Zahid
This code will count frequency and remove duplicate elements:
此代码将计算频率并删除重复元素:
from collections import Counter
str1='the cat sat on the hat hat'
int_list=str1.split();
unique_list = []
for el in int_list:
    if el not in unique_list:
        unique_list.append(el)
    else:
        print "Element already in the list"
print unique_list
c=Counter(int_list)
c.values()
c.keys()
print c
回答by alan
回答by Diogo Eichert
Your solution is correct, but your outer loop is still longer than needed. You don't need to compare the last element with anything else because it's been already compared with all the others in the previous iterations. Your inner loop still prevents that, but since we're talking about collision detection you can save the unnecessary check.
您的解决方案是正确的,但您的外循环仍然比需要的要长。您不需要将最后一个元素与其他任何元素进行比较,因为它已经在之前的迭代中与所有其他元素进行了比较。您的内部循环仍然可以防止这种情况发生,但是由于我们正在讨论碰撞检测,因此您可以省去不必要的检查。
Using the same language you used to illustrate your algorithm, you'd come with something like this:
使用您用来说明算法的相同语言,您会得到如下内容:
for (int i = 0, i < mylist.size() - 1; ++i)
    for (int j = i + 1, j < mylist.size(); --j)
        compare(mylist[i], mylist[j])

