除非没有人能够超越我的解决方案或任何优秀而简洁的Python解决方案,否则我不会接受自己的答案。
但对于任何有兴趣了解一些数字的人:
from random import randint
from timeit import timeit
def grismar(a: set, b: set):
h, i, t = set(), set(), b.copy()
for x in a:
if x in t:
i.add(x)
t.remove(x)
else:
h.add(x)
return h, i, t
def good(a: set, b: set):
return a - b, a & b, b - a
def better(a: set, b: set):
h, t = a - (i := a & b), b - i
return h, i, t
def ok(a: set, b: set):
return a - (a & b), a & b, b - (a & b)
from collections import defaultdict
def tim(a, b):
x2flags = defaultdict(int)
for x in a:
x2flags[x] = 1
for x in b:
x2flags[x] |= 2
result = [None, set(), set(), set()]
for x, flag in x2flags.items():
result[flag].add(x)
return result[1], result[3], result[2]
def pychopath(a, b):
h, t = set(), b.copy()
h_add = h.add
t_remove = t.remove
i = {x for x in a
if x in t and not t_remove(x) or h_add(x)}
return h, i, t
def enke(a, b):
t = b - (i := a - (h := a - b))
return h, i, t
xs = set(randint(0, 10000) for _ in range(10000))
ys = set(randint(0, 10000) for _ in range(10000))
g = (f(xs, ys) for f in (grismar, good, better, ok, tim, enke))
l = set(tuple(tuple(sorted(s)) for s in t) for t in g)
assert len(l) == 1, 'functions are equivalent'
timeit(lambda: grismar(xs, ys), number=500)
print('a - b, a & b, b - a ', timeit(lambda: good(xs, ys), number=10000))
print('a - (i := a & b), b - i ', timeit(lambda: better(xs, ys), number=10000))
print('a - (a & b), a & b, b - (a & b) ', timeit(lambda: ok(xs, ys), number=10000))
print('tim ', timeit(lambda: tim(xs, ys), number=10000))
print('grismar ', timeit(lambda: grismar(xs, ys), number=10000))
print('pychopath ', timeit(lambda: pychopath(xs, ys), number=10000))
print('b - (i := a - (h := a - b)) ', timeit(lambda: enke(xs, ys), number=10000))
结果:
a - b, a & b, b - a 5.6963334
a - (i := a & b), b - i 5.3934624
a - (a & b), a & b, b - (a & b) 9.7732018
tim 16.3080373
grismar 7.709292500000004
pychopath 6.76331460000074
b - (i := a - (h := a - b)) 5.197220600000001
到目前为止,@enke在评论中提出的优化方案似乎是最优的:
t = b - (i := a - (h := a - b))
return h, i, t
编辑:添加了@Pychopath的结果,它确实比我的结果快得多,尽管@enke的结果仍然是最优秀的(也很可能不只是用Python)。如果@enke发布他们自己的答案,我会很乐意接受它作为答案。
h,t = a -(i:= a&b),b-i
比h,i,t = a-b,a&b,b-a
快大约1.5-2倍。令人惊讶的是,h,i,t = a -(a&b),a&b,b -(a&b)
稍微但一致地比第二种方法更快。通过在a
上迭代并在b
中进行成员检查来创建h
和i
的循环方法可预测地表现不佳(2-6倍),比第一种方法慢。 - Pranav Hosangadii
会比重新评估(a&b)
慢两倍。 - Grismara - b
和b - a
的方法略慢于通过a - (a&b)
和b - (a&b)
的方法,这令人惊讶,因为需要计算两次交集。a-i,b-i
始终比两者都快。 - Pranav Hosangadi4.3:2.4:3.6
,所以我同意a - i, b - i
的方法要快得多。在 Python 中编写循环解决方案,我可以达到约 4.6,但我无法击败上述任何一种方法。当然,使用 C 函数可能会更好。 - Grismarset.difference
:t = b - (i:= a - (h:= a - b))
。当交集很大时,这个似乎执行得更快。 - user7864386