我正在尝试比较两个列表以确定一个是否是另一个列表的旋转(循环置换),例如:
a = [1, 2, 3]
b = [1, 2, 3] or [2, 3, 1] or [3, 1, 2]
是所有比赛,而:
b = [3, 2, 1] is not
要做到这一点,我有以下代码:
def _matching_lists(a, b):
return not [i for i, j in zip(a,b) if i != j]
def _compare_rotated_lists(a, b):
rotations = [b[i:] + b[:i] for i in range(len(b))]
matches = [i for i in range(len(rotations)) if _matching_lists(a, rotations[i])]
return matches
这将构建b的所有可能旋转的列表,然后比较每个旋转。是否可以在不构建中间列表的情况下执行此操作?性能并不重要,因为列表通常只有四个项目。我主要关心的是代码的清晰度。
列表的长度始终相同。
最佳答案(保持匹配轮换列表)似乎是:
def _compare_rotated_lists(a, b):
return [i for i in range(len(b)) if a == b[i:] + b[:i]]
答案 0 :(得分:7)
您不需要_matching_lists
功能,因为您可以使用==
:
>>> [1,2,3] == [1,2,3]
True
>>> [1,2,3] == [3,1,2]
False
我建议在找到匹配后立即使用any()
返回,并使用生成器表达式来避免在内存中构建旋转列表:
def _compare_rotated_lists(a, b):
"""Return `True` if the list `a` is equal to a rotation of the list `b`."""
return any(a == b[i:] + b[:i] for i in range(len(b)))
您可以考虑检查列表的长度是否相同,以便快速拒绝简单的案例。
return len(a) == len(b) and any(a == b[i:] + b[:i] for i in range(len(b)))
正如评论中所讨论的,如果您知道a
和b
的元素是可清除的,则可以使用collections.Counter
进行初始比较:
return Counter(a) == Counter(b) and any(a == b[i:] + b[:i] for i in range(len(b)))
如果您知道a
和b
的元素具有可比性,则可以使用sorted
进行初始比较:
return sorted(a) == sorted(b) and any(a == b[i:] + b[:i] for i in range(len(b)))
答案 1 :(得分:2)
如果我理解正确,您想要查找b
是a
的排列,而不是a
的排列?这是一个非常简单,可读和通用的解决方案:
>>> from itertools import permutations
>>> a = (1, 2, 3)
>>> b = (3, 1, 2)
>>> c = (3, 2, 1)
>>> results = set(permutations(a)) - set((a, tuple(sorted(a, reverse=True))))
>>> b in results
True
>>> c in results
False
答案 2 :(得分:1)
怎么样:
def canon(seq):
n = seq.index(min(seq))
return seq[n:] + seq[:n]
def is_rotation(a, b):
return canon(a) == canon(b)
print is_rotation('abcd', 'cdab') # True
print is_rotation('abcd', 'cdba') # False
无需生成所有轮换,只是为了确定两个列表是否相互轮换。
答案 3 :(得分:0)
我用一些例子测试了这段代码,但效果很好。
def compare(a,b):
firstInA = a[0]
firstInB = b.index(firstInA)
secondInA = a[1]
secondInB = b.index(secondInA)
if (secondInB == firstInB + 1) or (secondInB == 0 and firstInB == 2):
return True
else:
return False
我试过了:
a = [1,2,3]
b = [1,2,3]
print(compare(a,b))
c = [1,2,3]
d = [3,1,2]
print(compare(c,d))
e = [1,2,3]
f = [3,2,1]
print(compare(e,f))
他们返回True
,True
,False
这仅适用于大小为3的列表。如果您需要更多,请在if
语句中添加thirdInA和thirdInB,并且您将始终需要一个小于列表长度的列表,因为如果您知道全部但是有一个到位,那么最后只剩下现场了。