更优雅的表达方式((x == a和y == b)或(x == b和y == a))?

问题描述 投票:82回答:10

我正在尝试在Python中评估((x == a and y == b) or (x == b and y == a)),但似乎有些冗长。有没有更优雅的方法?

python boolean-logic
10个回答
125
投票

如果元素是可哈希的,则可以使用集合:

{a, b} == {y, x}

2
投票

似乎OP仅关注两个变量的情况,但是由于StackOverflow也适用于以后搜索相同问题的人员,因此我将在这里尝试详细解决通用情况;先前的一个答案已经包含使用def test_fun(x, y): test_set = {(a, b), (b, a)} return (x, y) in test_set 的通用答案,但是该方法会导致itertools.permutations()比较,因为存在O(N*N!)排列,每个排列都有N!个项目。 (这是此答案的主要动机)

首先,让我们总结一下先前答案中的某些方法如何应用于一般情况,以此作为本文介绍方法的动力。我将使用N来引用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!),因此也不适合大量输入;在我的机器上,一万个项目可能要花一秒钟-但是使用较小的输入项(例如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-基于方法,如果由于值无法排序而导致失败。


53
投票

我认为最好的方法是将它们打包成元组:

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

我之所以选择使用集合,是因为我正在执行成员资格查找,并且从概念上讲,集合比该元组更适合该用例。如果您在特定用例中测量了两种结构之间的显着差异,请选择速度更快的一种。我认为性能不是这里的因素。


27
投票

Tuples使它更具可读性:

(x, y) == (a, b) or (x, y) == (b, a)

这提供了一个线索:我们正在检查列表x, y是否等于列表a, b,但忽略了排序。这就是设置平等!

{x, y} == {a, b}

25
投票

如果项目不可散列,但支持排序比较,则可以尝试:

sorted((x, y)) == sorted((a, b))

23
投票

如果这些是数字,则可以使用(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))清晰,安全且更笼统。


19
投票

作为对两个以上变量的概括,我们可以使用itertools.permutations。那代替

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])

18
投票

我认为,最优雅的方式是

(x, y) in itertools.permutations([a, b])

[这比使用集(即(x, y) in ((a, b), (b, a)) )更好,如其他答案所示,因为我们不需要考虑变量是否可哈希。


14
投票

您可以使用元组表示数据,然后检查是否包含集合,例如:

{a, b} == {y, x}

8
投票

您已经获得了最具可读性的解决方案。还有其他表达方式,也许用更少的字符,但是阅读起来却不那么直接。

取决于值实际代表的最佳选择是将口述名称包裹在函数中。另外或另外,您可以在专用的高级类对象中对对象x,y和a,b进行建模,然后可以在类相等性检查方法或专用的自定义函数中将它们与比较逻辑进行比较。

© www.soinside.com 2019 - 2024. All rights reserved.