我正在与Codeskulptor合作解决岩石碰撞问题。我想检查岩石之间的碰撞,我的岩石列在清单中。我想出了构建组合列表然后检查碰撞的解决方案。 我没有itertools可用。 我的组合列表是这样创建的:
def combinations(items):
n_items = [(n,item) for n,item in enumerate(items)]
return [(item,item2) for n,item in n_items for m,item2 in n_items[n:] if n != m]
letters = ['A','B','C','D']
print combinations(letters)
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]
结果还可以。
在尝试使用函数之前,我尝试在一个衬里中执行此操作:
def combinations2(items):
return [(item,item2) for n,item in enumerate(items) for m,item2 in enumerate(items[n:]) if n != m]
letters = ['A','B','C','D']
print combinations2(letters)
但结果完全不同而且错误:
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'B'), ('B', 'D'), ('C', 'C'), ('C', 'D'), ('D', 'D')]
列表理解对我来说仍然是一个黑魔法。我无法解释这种行为,想了解错误了。 我知道我的双线解决方案要快得多,因为枚举只执行一次而不是使用。但错误的输出对我来说是无法解释的,特别是当缺少BC时,BB CC DD会在AA缺失的同时丢失。
有人可以帮助我吗?
答案 0 :(得分:6)
理解列表理解时要做的第一件事是将其扩展为常规的for
循环集。从左到右阅读循环并相应地嵌套。
工作代码:
def combinations(items):
n_items = []
for n,item in enumerate(items):
n_items.append((n,item))
result = []
for n, item in n_items:
for m, item2 in n_items[n:]:
if n != m:
result.append((item, item2))
return result
并且您的尝试无效:
def combinations2(items):
result = []
for n, item in enumerate(items):
for m, item2 in enumerate(items[n:]):
if n != m:
result.append((item, item2))
return result
也许这样可以更容易地看出两个版本之间出现了什么问题。
您的版本切片只是 items
,而不是enumerate()
生成的索引。原始版本会将[(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D')]
切换为[(1, 'B'), (2, 'C'), (3, 'D')]
等,而您的版本会将该切片重新编号为[(0, 'B'), (1, 'C'), (2, 'D')]
。这反过来会导致错误的输出。
通过向enumerate()
函数添加第二个参数来启动更高索引处的内部循环,该函数是开始编号的索引:
def combinations2(items):
result = []
for n, item in enumerate(items):
for m, item2 in enumerate(items[n:], n):
if n != m:
result.append((item, item2))
return result
回到单行:
def combinations2(items):
return [(item, item2) for n, item in enumerate(items) for m, item2 in enumerate(items[n:], n) if n != m]
然后这可以正常工作:
>>> def combinations2(items):
... return [(item, item2) for n, item in enumerate(items) for m, item2 in enumerate(items[n:], n) if n != m]
...
>>> letters = ['A','B','C','D']
>>> combinations2(letters)
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]
请注意,您可以将其简化为进一步; n == m
True
的唯一时间是每个内循环的第一次迭代。只需将内部列表的items
列表进一步切片;从1开始外部enumerate()
,放弃内部enumerate()
并放弃n != m
测试:
def combinations3(items):
result = []
for n, item in enumerate(items, 1):
for item2 in items[n:]:
result.append((item, item2))
return result
或作为列表理解:
def combinations3(items):
return [(item, item2) for n, item in enumerate(items, 1) for item2 in items[n:]]
答案 1 :(得分:1)
跳过迭代器中的冲突。
>>> letter = ['A', 'B', 'C', 'D']
>>> list ( (x,y) for n, x in enumerate(letter) for y in letter[n+1:])
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]
答案 2 :(得分:0)
假设您只想获得组合列表。
def combinations2(items):
return filter(lambda (i,j): i <> j, [(i,j) for i in items for j in items])
letters = ['A','B','C','D']
print combinations2(letters)
我得到的输出是:
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'A'), ('B', 'C'), ('B', 'D'), ('C', 'A'), ('C', 'B'), ('C', 'D'), ('D', 'A'), ('D', 'B'), ('D', 'C')]