提问人:LetEpsilonBeLessThanZero 提问时间:10/17/2019 最后编辑:LetEpsilonBeLessThanZero 更新时间:6/17/2020 访问量:12203
有没有更优雅的表达方式((x == a and y == b) or (x == b and y == a))?
Is there a more elegant way to express ((x == a and y == b) or (x == b and y == a))?
答:
如果元素是可散列的,则可以使用集合:
{a, b} == {y, x}
评论
{1, 1, 2} == {1, 2, 2}
sorted
Counter
我认为你能得到的最好的办法是将它们打包成元组:
if (a, b) == (x, y) or (a, b) == (y, x)
或者,也许将其包装在集合查找中
if (a, b) in {(x, y), (y, x)}
既然有几条评论提到了它,我就做了一些计时,当查找失败时,元组和集合在这里的表现似乎相同:
from timeit import timeit
x = 1
y = 2
a = 3
b = 4
>>> timeit(lambda: (a, b) in {(x, y), (y, x)}, number=int(5e7))
32.8357742
>>> timeit(lambda: (a, b) in ((x, y), (y, x)), number=int(5e7))
31.6169182
尽管当查找成功时,元组实际上会更快:
x = 1
y = 2
a = 1
b = 2
>>> timeit(lambda: (a, b) in {(x, y), (y, x)}, number=int(5e7))
35.6219458
>>> timeit(lambda: (a, b) in ((x, y), (y, x)), number=int(5e7))
27.753138700000008
我之所以选择使用集合,是因为我正在进行成员资格查找,从概念上讲,集合比元组更适合该用例。如果您在特定用例中测量了两种结构之间的显着差异,请使用更快的结构。不过,我不认为性能是一个因素。
评论
if (a, b) in ((x, y), (y, x))
set
元组使其更具可读性:
(x, y) == (a, b) or (x, y) == (b, a)
这给出了一个线索:我们正在检查序列是否等于序列,但忽略了排序。那只是设置平等!x, y
a, b
{x, y} == {a, b}
评论
,
创建一个元组,而不是一个列表。so 和 是元组,与 和 相同。(x, y)
(a, b)
x, y
a, b
list
您可以使用元组来表示数据,然后检查集合包含,例如:
def test_fun(x, y):
test_set = {(a, b), (b, a)}
return (x, y) in test_set
评论
如果项目不可散列,但支持排序比较,则可以尝试:
sorted((x, y)) == sorted((a, b))
评论
complex
如果这些是数字,则可以使用 .(x+y)==(a+b) and (x*y)==(a*b)
如果这些是可比较的项目,则可以使用 。min(x,y)==min(a,b) and max(x,y)==max(a,b)
但清晰、安全且更笼统。((x == a and y == b) or (x == b and y == a))
评论
在我看来,最优雅的方式是
(x, y) in ((a, b), (b, a))
这是比使用集合更好的方法,即 ,如其他答案所示,因为我们不需要考虑变量是否可散列。{a, b} == {y, x}
评论
作为对两个以上变量的推广,我们可以使用 itertools.permutations
。也就是说,代替
(x == a and y == b and z == c) or (x == a and y == c and z == b) or ...
我们可以写
(x, y, z) in itertools.permutations([a, b, c])
当然还有两个变量版本:
(x, y) in itertools.permutations([a, b])
评论
O(N*N!)
O(N^2)
您已经得到了最易读的解决方案。还有其他方法可以表达这一点,也许用更少的字符,但它们不那么直接阅读。
根据这些值实际表示的内容,最好的办法是将支票包装在一个带有说话名称的函数中。或者,或者另外,您可以在专用的更高类对象中对对象 x,y 和 a,b 进行建模,然后可以将其与类相等性检查方法或专用自定义函数中的比较逻辑进行比较。
OP 似乎只关注两个变量的情况,但由于 StackOverflow 也适用于稍后搜索相同问题的人,因此我将尝试在这里详细解决一般情况;前面的一个答案已经包含一个使用 的通用答案,但这种方法会导致比较,因为每个项目都有排列。(这是这个答案的主要动机)itertools.permutations()
O(N*N!)
N!
N
首先,让我们总结一下前面答案中的一些方法如何应用于一般情况,作为这里介绍的方法的动机。我将使用 to refer to 和 to refer to ,它可以是任意(但相等)长度的元组。A
(x, y)
B
(a, b)
set(A) == set(B)
速度很快,但仅当值是可哈希的,并且可以保证其中一个元组不包含任何重复值时才有效。(例如,正如@user2357112在@Daniel Mesejo的回答下指出的那样){1, 1, 2} == {1, 2, 2}
前面的方法可以通过使用带有计数的字典而不是集合来扩展为处理重复值:(这仍然有所有值都需要是可散列的限制,因此例如可变值将不起作用)list
def counts(items):
d = {}
for item in items:
d[item] = d.get(item, 0) + 1
return d
counts(A) == counts(B)
sorted(A) == sorted(B)
不需要可哈希值,但速度稍慢,需要可排序的值。(例如 行不通)complex
A in itertools.permutations(B)
不需要可散列或可排序的值,但如前所述,它具有复杂性,因此即使只有 11 个项目,也可能需要一秒钟才能完成。O(N*N!)
那么,有没有办法做到一般,但做得更快呢?为什么是,通过“手动”检查每个项目的数量是否相同:(这个的复杂性是,所以这对大输入也不好;在我的机器上,10k 个项目可能需要一秒钟以上 - 但对于较小的输入,比如 10 个项目,这与其他项目一样快)O(N^2)
def unordered_eq(A, B):
for a in A:
if A.count(a) != B.count(a):
return False
return True
为了获得最佳性能,可能需要先尝试基于 -的方法,如果由于不可哈希值而失败,则回退到基于 -的方法,如果由于不可排序的值而失败,则最后回退到基于 -的方法。dict
sorted
count
评论
x,y, a,b
x,y
a,b
x,y, a,b
((x == a and y == b) or (x == b and y == a))