假设我有一个我要比较的数组/列表.在我更熟悉的语言中,我会做类似的事情
for (int i = 0, i < mylist.size(); i++)
for (int j = i + 1, j < mylist.size(); j++)
compare(mylist[i], mylist[j])
Run Code Online (Sandbox Code Playgroud)
这确保我们只比较每对一次.对于某些上下文,我正在对列表中包含的一堆对象进行冲突检测.对于检测到的每个碰撞,描述碰撞的小"碰撞"对象被附加到列表,然后另一个例程循环解决每个碰撞(取决于两个碰撞对象的性质).显然,我只想报告每次碰撞一次.
现在,这样做的pythonic方法是什么,因为Python倾向于使用迭代器而不是循环索引?
我有以下(错误)代码:
for this in mylist:
for that in mylist:
compare(this, that)
Run Code Online (Sandbox Code Playgroud)
但这显然会在每次碰撞中发生两次,这在尝试解决它们时会导致一些奇怪的行为.那么这里的pythonic解决方案是什么?
pok*_*oke 102
当然,这将生成每对两次,因为每个for
循环将遍历列表中的每个项目.
你可以在这里使用一些itertools魔法来生成所有可能的组合:
import itertools
for a, b in itertools.combinations(mylist, 2):
compare(a, b)
Run Code Online (Sandbox Code Playgroud)
itertools.combinations
将每个元素与迭代中的每个其他元素配对,但只能配对一次.
你仍然可以使用基于索引的项目访问来编写它,相当于你习惯使用的嵌套for
循环:
for i in range(len(mylist)):
for j in range(i + 1, len(mylist)):
compare(mylist[i], mylist[j])
Run Code Online (Sandbox Code Playgroud)
当然,这可能看起来不那么好和pythonic,但有时这仍然是最容易和最易理解的解决方案,所以你不应回避解决这样的问题.
shx*_*hx2 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
Run Code Online (Sandbox Code Playgroud)
我认为在外部循环上使用枚举并在内部循环上使用索引对列表进行切片是相当Pythonic的:
for index, this in enumerate(mylist):
for that in mylist[index+1:]:
compare(this, that)
Run Code Online (Sandbox Code Playgroud)