繁体   English   中英

有没有更优雅的方式来表达 ((x == a and y == b) 或 (x == b and y == a))?

[英]Is there a more elegant way to express ((x == a and y == b) or (x == b and y == a))?

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

如果元素是可散列的,则可以使用集合:

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

我认为你能得到的最好的是将 package 变成元组:

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

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

元组使其更具可读性:

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

这给出了一个线索:我们正在检查序列x, y是否等于序列a, b但忽略排序。 那只是设定平等!

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

在我看来,最优雅的方式是

(x, y) in ((a, b), (b, a))

这是比使用集合更好的方法,即{a, b} == {y, x} ,如其他答案所示,因为我们不需要考虑变量是否是可散列的。

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

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

如果这些是数字,您可以使用(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))是清晰、安全和更通用的。

作为对两个以上变量的概括,我们可以使用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])

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

def test_fun(x, y):
    test_set = {(a, b), (b, a)}

    return (x, y) in test_set

您已经获得了最易读的解决方案 还有其他方式来表达这一点,也许用更少的字符,但它们不那么直截了当。

根据实际代表的值,您最好的选择是将支票包装在 function 中,并带有口语名称 Alternatively or in addition, you can model the objects x,y and a,b each in dedicated higher class objects that you then can compare with the logic of the comparison in a class equality check method or a dedicated custom function.

似乎 OP 只关心两个变量的情况,但由于 StackOverflow 也适用于稍后搜索相同问题的人,所以我将尝试在这里更详细地解决一般情况; 以前的一个答案已经包含使用itertools.permutations()的通用答案,但是该方法导致O(N*N!)比较,因为有N! 每个有N个项目的排列。 (这是这个答案的主要动机)

首先,让我们总结一下先前答案中的一些方法如何应用于一般情况,作为此处介绍的方法的动机。 我将使用A来引用(x, y)B来引用(a, b) ,它可以是任意(但相等)长度的元组。

set(A) == set(B)速度很快,但仅在值是可散列的并且您可以保证其中一个元组不包含任何重复值时才有效。 (例如{1, 1, 2} == {1, 2, 2} ,正如@user2357112在@Daniel Mesejo 的回答下指出的那样)

以前的方法可以通过使用带有计数的字典而不是集合来扩展以处理重复值:(这仍然具有所有值都需要是可散列的限制,因此例如像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)不需要可散列或可排序的值,但如前所述,它具有O(N*N!)复杂性,因此即使只有 11 个项目,也可能需要一秒钟才能完成。

那么,有没有办法做到通用,但速度要快得多? 为什么是的,通过“手动”检查每个项目的数量是否相同:(这个项目的复杂性是O(N^2) ,所以这也不适用于大输入;在我的机器上,10k 个项目可以占用超过一秒钟 - 但输入较小,如 10 个项目,这与其他项目一样快)

def unordered_eq(A, B):
    for a in A:
        if A.count(a) != B.count(a):
            return False
    return True

为了获得最佳性能,人们可能想先尝试基于dict的方法,如果由于不可散列的值而失败,则回退到基于sorted的方法,如果由于不可散列的值而失败,最后回退到基于count的方法不可排序的值。

如果我们不是在寻找 Python 语法特定答案

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM