说我有一个我要比较的数组/列表。在我更熟悉的语言中,我会做类似的事情
for (int i = 0, i < mylist.size(); i++)
for (int j = i + 1, j < mylist.size(); j++)
compare(mylist[i], mylist[j])
这确保我们只比较每对一次。对于某些上下文,我正在对列表中包含的一堆对象进行冲突检测。对于检测到的每个碰撞,描述碰撞的小“碰撞”对象被附加到列表,然后另一个例程循环解决每个碰撞(取决于两个碰撞对象的性质)。显然,我只想报告每次碰撞一次。
现在,这样做的pythonic方法是什么,因为Python倾向于使用迭代器而不是循环索引?
我有以下(错误)代码:
for this in mylist:
for that in mylist:
compare(this, that)
但是这显然会在每次碰撞中发生两次,这在尝试解决它们时会导致一些奇怪的行为。那么这里的pythonic解决方案是什么?
答案 0 :(得分:92)
当然,这将生成每对两次,因为每个for
循环将遍历列表中的每个项目。
你可以在这里使用一些itertools魔法来生成所有可能的组合:
import itertools
for a, b in itertools.combinations(mylist, 2):
compare(a, b)
itertools.combinations
会将每个元素与iterable中的每个其他元素配对,但只会一次。
你仍然可以使用基于索引的项目访问来编写它,相当于你习惯使用嵌套的for
循环:
for i in range(len(mylist)):
for j in range(i + 1, len(mylist)):
compare(mylist[i], mylist[j])
当然,这可能看起来并不像pythonic那样好,但有时候这仍然是最容易理解的解决方案,所以你不应该回避解决这类问题。
答案 1 :(得分:21)
使用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
答案 2 :(得分:4)
我认为在外部循环上使用enumerate并使用索引来切割内部循环上的列表非常Pythonic:
for index, this in enumerate(mylist):
for that in mylist[index+1:]:
compare(this, that)
答案 3 :(得分:-1)
您的解决方案是正确的,但是您的外循环仍然比所需的时间更长。您无需将最后一个元素与其他任何元素进行比较,因为在先前的迭代中已经将它与所有其他元素进行了比较。您的内部循环仍然可以防止这种情况,但是由于我们在谈论碰撞检测,因此可以节省不必要的检查。
使用与用于说明算法的语言相同的语言,您会得到以下类似信息:
for (int i = 0, i < mylist.size() - 1; ++i)
for (int j = i + 1, j < mylist.size(); --j)
compare(mylist[i], mylist[j])
答案 4 :(得分:-3)
此代码将计算频率并删除重复元素:
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