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

Let*_*ero 105 python boolean-logic

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

Dan*_*ejo 146

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

{a, b} == {y, x}
Run Code Online (Sandbox Code Playgroud)

  • @Graham不,不是,因为在右手设置中恰好有两个项目。如果两者均为a,则不存在b,并且如果两者均为b,则不存在a,并且在两种情况下,集合均不能相等。 (18认同)
  • 另一方面,如果我们在每一侧都有*三个*元素,并且需要测试它们是否可以一对一地匹配,则集将不起作用。{1,1,2} == {1,2,2} 此时,您需要“已排序”或“计数器”。 (12认同)
  • 我发现阅读起来很棘手(不要将“ {}”读为“()”)。足以评论它-然后失去目的。 (10认同)
  • 我知道它是python,但是创建两个新集只是比较值对我来说似乎有点过头了……只需定义一个执行此操作并在需要时调用的函数即可。 (8认同)
  • @marxin一个函数将比2个简单的set构造更大的杀伤力。而且4个参数的可读性较低。 (5认同)
  • @Andy:除了set构造函数实际上不是那样工作的,所以您会得到TypeError。`set([x,y])== set([a,b])`可以工作,但是与`{x,y} == {a,b}`相比,它运行较慢,需要更多的键入,并且涉及语法上的嵌套更多(更不清晰,尤其是当元素表达式比“ x”和“ y”更复杂时)。 (4认同)
  • 但这也将覆盖等于a或等于b的两个值。OP可能希望这样做,也许不是。 (3认同)
  • 喔好吧。我的错,对不起。 (3认同)
  • @marxin:您的直觉可能基于静态或JIT编译的语言实现,可以轻松地内联函数。[在CPython中,引入一个函数相对于内联执行它几乎使测试的成本增加了一倍,有时比构建集更昂贵。](https://ideone.com/3alqci) (2认同)

Car*_*ate 57

我认为最好的办法是将它们包装到元组中:

if (a, b) == (x, y) or (a, b) == (y, x)
Run Code Online (Sandbox Code Playgroud)

或者,也许将其包装在集合中

if (a, b) in {(x, y), (y, x)}
Run Code Online (Sandbox Code Playgroud)

正因为有几条评论提到了它,所以我做了一些计时,当查找失败时,元组和集合在这里的表现相同:

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
Run Code Online (Sandbox Code Playgroud)

尽管查找成功时元组实际上更快:

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
Run Code Online (Sandbox Code Playgroud)

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

  • @Brilliand如果您担心性能影响,那么Python不是您想要的语言。:-D (18认同)
  • 元组方法看起来很干净。我会担心使用集合对性能的影响。但是,您可以在((x,y),(y,x))中执行if(a,b)吗? (12认同)

Tho*_*mas 30

元组使其更具可读性:

(x, y) == (a, b) or (x, y) == (b, a)
Run Code Online (Sandbox Code Playgroud)

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

{x, y} == {a, b}
Run Code Online (Sandbox Code Playgroud)


jas*_*per 26

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

sorted((x, y)) == sorted((a, b))
Run Code Online (Sandbox Code Playgroud)

  • @CarlWitthoft:否。有些类型可以哈希但不能排序:例如“复杂”。 (5认同)

lhf*_*lhf 25

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

  • 哈哈,对称多项式ftw! (2认同)
  • 我认为这会产生溢出错误的风险。 (2认同)
  • 这是正确的答案,尤其是最后一句话。保持简单,这不需要多个新的可迭代对象或类似的东西。对于那些想使用集合的人,请看一下[集合对象的实现](https://github.com/python/cpython/blob/master/Objects/setobject.c),然后想象一下尝试在其中运行紧密的循环... (2认同)
  • @RazvanSocol OP并未说明数据类型是什么,并且此答案确实限定了类型相关的解决方案。 (2认同)

小智 22

我认为,最优雅的方式是

(x, y) in ((a, b), (b, a))
Run Code Online (Sandbox Code Playgroud)

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

  • @ scohe001它使用一个元组,较早的答案使用一个集合。先前的答案确实考虑了此解决方案,但拒绝将其列为建议。 (4认同)

a_g*_*est 20

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

(x == a and y == b and z == c) or (x == a and y == c and z == b) or ...
Run Code Online (Sandbox Code Playgroud)

我们可以写

(x, y, z) in itertools.permutations([a, b, c])
Run Code Online (Sandbox Code Playgroud)

当然还有两个变量版本:

(x, y) in itertools.permutations([a, b])
Run Code Online (Sandbox Code Playgroud)

  • 好答案。值得指出的是(对于那些以前没有使用生成器做过很多事情的人),这是非常高效的内存,因为一次仅创建一个排列,并且“ in”检查将停止并在a之后立即返回True。找到匹配项。 (3认同)
  • 还值得指出的是,该方法的复杂度是“O(N*N!)”;对于 11 个变量,这可能需要一秒多的时间才能完成。(我发布了一个更快的方法,但它仍然需要“O(N^2)”,并且开始在 10k 变量上花费一秒;所以看来这可以快速完成或一般完成(wrt.哈希性/可排序性),但是不是两者都:P) (2认同)

小智 15

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

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

    return (x, y) in test_set
Run Code Online (Sandbox Code Playgroud)

  • 我将其作为一个单行代码并列出一个清单(用于非哈希项目),我认为这是最好的答案。(尽管我是一个完整的Python新手)。 (3认同)

Fra*_*ins 9

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

根据值实际代表最好的选择的方式,是将支票包装在一个具有语音名称的函数中。替代地或另外,您可以在专用的高级类对象中对对象x,y和a,b进行建模,然后可以在类相等性检查方法或专用的自定义函数中将它们与比较逻辑进行比较。


Ale*_*amo 5

似乎 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)
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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