我正在尝试使用((x == a and y == b) or (x == b and y == a))
Python 进行评估,但似乎有些冗长。有没有更优雅的方式?
((x == a and y == b) or (x == b and y == a))
看起来有些怪异,但是1)它的意图非常清晰,所有非Python程序员(不是神秘主义者)都可以理解。2)解释器/编译器将始终能够很好地处理它,并且从根本上讲,它永远不会导致性能不佳的代码,与备择方案。因此,“更优雅”也可能有严重的弊端。
我正在尝试使用((x == a and y == b) or (x == b and y == a))
Python 进行评估,但似乎有些冗长。有没有更优雅的方式?
((x == a and y == b) or (x == b and y == a))
看起来有些怪异,但是1)它的意图非常清晰,所有非Python程序员(不是神秘主义者)都可以理解。2)解释器/编译器将始终能够很好地处理它,并且从根本上讲,它永远不会导致性能不佳的代码,与备择方案。因此,“更优雅”也可能有严重的弊端。
Answers:
如果元素是可哈希的,则可以使用集合:
{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
在@Brilliand的元组解决方案的答案中,是否有任何理由更喜欢该解决方案?
元组使其更具可读性:
(x, y) == (a, b) or (x, y) == (b, a)
这提供了一个线索:我们正在检查序列x, y
是否等于序列,a, b
但忽略了排序。那就是设置平等!
{x, y} == {a, b}
,
创建一个元组,而不是列表。所以(x, y)
和(a, b)
是元组,与x, y
和相同a, b
。
list
类型。之所以进行编辑,是因为确实令人困惑。
我认为,最优雅的方式是
(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!)
:对于11个变量,这可能需要一秒钟才能完成。(我发布了一个更快的方法,但仍然需要O(N^2)
,并开始处理10k变量上的一秒钟;因此看来这可以快速完成,或者通常可以完成(可写性/可排序性),但不能同时使用:P)
看来,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)
,因此这对于大输入也不是一件好事;在我的机器上,一万个项目可能要花一秒钟的时间,但是较小的输入(例如10个项目,这与其他项目一样快)
def unordered_eq(A, B):
for a in A:
if A.count(a) != B.count(a):
return False
return True
为了获得最佳的性能,人们可能会想尝试的dict
第一个基于方法,回落到sorted
基于方法如果失败了,由于unhashable值,最后回落到count
基方法,如果太因unorderable值失败。
x,y, a,b
是:它们是整型数/浮点数/字符串,任意对象还是什么?如果它们是内置类型,并且可以同时保持它们x,y
和a,b
排序顺序,则可以避免第二个分支。请注意,创建集合将导致对四个元素中的每一个x,y, a,b
进行哈希处理,这可能是琐碎的,也可能不是琐碎的,或者对性能有影响,这完全取决于它们是什么类型的对象。