Python 肾盂可吸收差
我编写了一些代码来查找一个iterable中的所有项,而不是另一个iterable中的所有项,反之亦然。我最初使用的是内置的集合差异,但计算速度相当慢,因为每个集合中存储了数百万项。因为我知道最多会有几千个差异,所以我写了以下版本:Python 肾盂可吸收差,python,python-2.7,Python,Python 2.7,我编写了一些代码来查找一个iterable中的所有项,而不是另一个iterable中的所有项,反之亦然。我最初使用的是内置的集合差异,但计算速度相当慢,因为每个集合中存储了数百万项。因为我知道最多会有几千个差异,所以我写了以下版本: def differences(a_iter, b_iter): a_items, b_items = set(), set() def remove_or_add_if_none(a_item, b_item, a_set, b_set):
def differences(a_iter, b_iter):
a_items, b_items = set(), set()
def remove_or_add_if_none(a_item, b_item, a_set, b_set):
if a_item is None:
if b_item in a_set:
a_set.remove(b_item)
else:
b_set.add(b)
def remove_or_add(a_item, b_item, a_set, b_set):
if a in b_set:
b_set.remove(a)
if b in a_set:
a_set.remove(b)
else:
b_set.add(b)
return True
return False
for a, b in itertools.izip_longest(a_iter, b_iter):
if a is None or b is None:
remove_or_add_if_none(a, b, a_items, b_items)
remove_or_add_if_none(b, a, b_items, a_items)
continue
if a != b:
if remove_or_add(a, b, a_items, b_items) or \
remove_or_add(b, a, b_items, a_items):
continue
a_items.add(a)
b_items.add(b)
return a_items, b_items
但是,上面的代码似乎不太符合python,因此我正在寻找替代方案或改进建议。我认为您的代码已损坏-请使用
[1,1]
和[1,2]
进行尝试,您会发现1
在一组中,而不是在另一组中
> print differences([1,1],[1,2])
(set([1]), set([2]))
您可以将其追溯到的效果,如果a!=b
test(假设在简单的集合差异中不存在排序)
如果没有这个测试,它可能会丢弃许多值,我认为您的方法不会比内置集更快。这个论点是这样的:你真的需要在内存中创建一个集合来保存所有的数据(你的错误是因为没有这样做)。朴素的集合方法创建两个集合。因此,您所能做的最好的事情就是节省一半的时间,并且您还必须使用python来完成可能是高效的c代码。我认为python集操作将是您从标准库中获得的最佳性能 问题可能在于您选择的特定实现,而不是数据结构和伴随操作本身。这里有一个替代实现,它应该可以为您提供更好的性能 对于序列较大的序列比较任务,尽可能避免将组成序列的对象放入用于比较的容器中——最好使用索引。如果序列中的对象是无序的,则对它们进行排序 例如,我使用数字python库来执行以下任务:
# a, b are 'fake' index arrays of type boolean
import numpy as NP
a, b = NP.random.randint(0, 2, 10), NP.random.randint(0, 2, 10)
a, b = NP.array(a, dtype=bool), NP.array(b, dtype=bool)
# items a and b have in common:
NP.sum(NP.logical_and(a, b))
# the converse (the differences)
NP.sum(NP.logical_or(a, b))
下面是一个更具python风格的解决方案:
a, b = set(a_iter), set(b_iter)
return a - b, b - a
Pythonic并不意味着快速,而是优雅易读
下面是一个可能更快的解决方案:
a, b = set(a_iter), set(b_iter)
# Get all the candidate return values
symdif = a.symmetric_difference(b)
# Since symdif has much fewer elements, these might be faster
return symdif - b, symdif - a
现在,关于用Python编写自定义“快速”算法而不是使用内置操作:这是一个非常糟糕的主意
set操作符经过了大量优化,并用C编写,通常比Python快得多。
您可以用C(或Cython)编写算法,但请记住Python的集合算法是由世界级的天才编写和优化的。
除非你非常擅长优化,否则这可能是不值得的。另一方面,如果你确实设法大大加快了速度,请分享你的代码;我打赌它有机会进入Python本身
要获得更现实的方法,请尝试取消对Python代码的调用。例如,如果您的对象具有自定义相等运算符,请找出删除该运算符的方法
但是不要抱太大的希望。处理数百万条数据总是需要很长时间。我不知道你在哪里使用这个,但也许让计算机忙上一分钟比花时间优化集合算法更好?你的集合比内置的集合差快多少?