Numpy 比较列表和提取某些数据的最佳实践
我有一个旧的电子邮件列表,应该更新为新的电子邮件列表 我需要最有效的方法来比较它们并选择从旧列表中删除的电子邮件 电子邮件列表存储在数据库中,因此我可以获得电子邮件ID(电子邮件是唯一的) 我使用的代码:Numpy 比较列表和提取某些数据的最佳实践,numpy,diff,python-3.7,Numpy,Diff,Python 3.7,我有一个旧的电子邮件列表,应该更新为新的电子邮件列表 我需要最有效的方法来比较它们并选择从旧列表中删除的电子邮件 电子邮件列表存储在数据库中,因此我可以获得电子邮件ID(电子邮件是唯一的) 我使用的代码: old_ids_list = [1, 2, 3] new_ids_list = [1, 2] old_emails_list = ['toto@gmail.com', 'lolo@gmail.com', 'momo@gmail.com'] new_emails_list = ['toto@gm
old_ids_list = [1, 2, 3]
new_ids_list = [1, 2]
old_emails_list = ['toto@gmail.com', 'lolo@gmail.com', 'momo@gmail.com']
new_emails_list = ['toto@gmail.com', 'lolo@gmail.com',]
if len(old_ids_list) == len(new_ids_list) & len(set(old_ids_list) & set(new_ids_list)) == len(old_ids_list):
pass
else:
deleted = numpy.setdiff1d(old_emails_list, new_emails_list, assume_unique=False)
这是一种好的做法吗?或者最好对循环使用
?为什么?你可以使用列表理解。正如你所说,电子邮件本身是独一无二的,我不确定你想用ID做什么,我们不需要转换成集合(如果我搞错了,请纠正我)
imho这种方法的优点是可读性好,不需要外部包
编辑要检查新列表是否与旧列表不同,有两个szenarios:
a) 如果已知新列表是旧列表的子列表,只需检查上文计算的
已删除中是否有任何元素。
b) 如果新列表中可能有新的电子邮件,请检查已删除的
是否包含任何电子邮件,如果没有,请另外检查len(新电子邮件列表)==len(旧电子邮件列表)
您可以使用列表理解。正如你所说,电子邮件本身是独一无二的,我不确定你想用ID做什么,我们不需要转换成集合(如果我搞错了,请纠正我)
imho这种方法的优点是可读性好,不需要外部包
编辑
要检查新列表是否与旧列表不同,有两个szenarios:
a) 如果已知新列表是旧列表的子列表,只需检查上文计算的已删除中是否有任何元素。
b) 如果新列表中可能有新的电子邮件,请检查已删除的
是否包含任何电子邮件,如果没有,请另外检查len(新电子邮件列表)==len(旧电子邮件列表)
首先,在if
条件下,您已经在做艰苦的工作,因此不需要事先进行测试。
第二,不清楚你的出发点是什么,是ID还是电子邮件,或者两者中的任何一个,以及你的终点
但似乎最干净的方法是一直使用set
我认为您可以使用ID(但同样的代码适用于电子邮件地址):
现在,让我们假设起点是两个列表
(同样,ID或电子邮件是不相关的,为了简单起见,我只假设ID),并假设您想知道添加和删除的项目。有两种可能的方法:
def diffs_set(a, b):
a = set(a)
b = set(b)
return a - b, b - a
对于某些输入大小,其计时如下所示:
funcs = diffs_set, diffs_loop, diffs_loop2, diffs_np
for n in (10, 100, 1000, 10000):
print(n)
old_items = list(range(1, n))
new_items = list(range(n - 1))
for func in funcs:
print(func.__name__)
%timeit func(old_items, new_items)
print()
# 10
# diffs_set
# The slowest run took 4.52 times longer than the fastest. This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 914 ns per loop
# diffs_loop
# 1000000 loops, best of 3: 1.97 µs per loop
# diffs_loop2
# 100000 loops, best of 3: 2.09 µs per loop
# diffs_np
# 10000 loops, best of 3: 65.6 µs per loop
# 100
# diffs_set
# 100000 loops, best of 3: 5.23 µs per loop
# diffs_loop
# 100000 loops, best of 3: 13.6 µs per loop
# diffs_loop2
# 10000 loops, best of 3: 116 µs per loop
# diffs_np
# The slowest run took 5.74 times longer than the fastest. This could mean that an intermediate result is being cached.
# 10000 loops, best of 3: 65.9 µs per loop
# 1000
# diffs_set
# 10000 loops, best of 3: 57.7 µs per loop
# diffs_loop
# 10000 loops, best of 3: 132 µs per loop
# diffs_loop2
# 100 loops, best of 3: 10.7 ms per loop
# diffs_np
# 1000 loops, best of 3: 374 µs per loop
# 10000
# diffs_set
# 1000 loops, best of 3: 818 µs per loop
# diffs_loop
# 1000 loops, best of 3: 1.6 ms per loop
# diffs_loop2
# 1 loop, best of 3: 1.06 s per loop
# diffs_np
# 100 loops, best of 3: 3.5 ms per loop
最重要的一点是,使用集合可以获得最快、最干净的方法。
需要注意的是,set
s甚至对于列表的理解也很有用,因为if
条件变为O(1)
(导致总体O(n)
)而不是O(n)
(导致总体O(n²)
)。
因为最昂贵的操作是在开始时实际构建集
,所以如果只需要a-b
或b-a
,列表理解可能会与仅使用集竞争,因为这样只需要一个set()
调用。
相反,基于NumPy的方法在这里没有竞争力。首先,在if
条件下,您已经在做艰苦的工作,因此不需要事先进行测试。
第二,不清楚你的出发点是什么,是ID还是电子邮件,或者两者中的任何一个,以及你的终点
但似乎最干净的方法是一直使用set
我认为您可以使用ID(但同样的代码适用于电子邮件地址):
现在,让我们假设起点是两个列表
(同样,ID或电子邮件是不相关的,为了简单起见,我只假设ID),并假设您想知道添加和删除的项目。有两种可能的方法:
def diffs_set(a, b):
a = set(a)
b = set(b)
return a - b, b - a
对于某些输入大小,其计时如下所示:
funcs = diffs_set, diffs_loop, diffs_loop2, diffs_np
for n in (10, 100, 1000, 10000):
print(n)
old_items = list(range(1, n))
new_items = list(range(n - 1))
for func in funcs:
print(func.__name__)
%timeit func(old_items, new_items)
print()
# 10
# diffs_set
# The slowest run took 4.52 times longer than the fastest. This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 914 ns per loop
# diffs_loop
# 1000000 loops, best of 3: 1.97 µs per loop
# diffs_loop2
# 100000 loops, best of 3: 2.09 µs per loop
# diffs_np
# 10000 loops, best of 3: 65.6 µs per loop
# 100
# diffs_set
# 100000 loops, best of 3: 5.23 µs per loop
# diffs_loop
# 100000 loops, best of 3: 13.6 µs per loop
# diffs_loop2
# 10000 loops, best of 3: 116 µs per loop
# diffs_np
# The slowest run took 5.74 times longer than the fastest. This could mean that an intermediate result is being cached.
# 10000 loops, best of 3: 65.9 µs per loop
# 1000
# diffs_set
# 10000 loops, best of 3: 57.7 µs per loop
# diffs_loop
# 10000 loops, best of 3: 132 µs per loop
# diffs_loop2
# 100 loops, best of 3: 10.7 ms per loop
# diffs_np
# 1000 loops, best of 3: 374 µs per loop
# 10000
# diffs_set
# 1000 loops, best of 3: 818 µs per loop
# diffs_loop
# 1000 loops, best of 3: 1.6 ms per loop
# diffs_loop2
# 1 loop, best of 3: 1.06 s per loop
# diffs_np
# 100 loops, best of 3: 3.5 ms per loop
最重要的一点是,使用集合可以获得最快、最干净的方法。
需要注意的是,set
s甚至对于列表的理解也很有用,因为if
条件变为O(1)
(导致总体O(n)
)而不是O(n)
(导致总体O(n²)
)。
因为最昂贵的操作是在开始时实际构建集
,所以如果只需要a-b
或b-a
,列表理解可能会与仅使用集竞争,因为这样只需要一个set()
调用。
相反,基于NumPy的方法在这里没有竞争力。到底什么是旧的
和新的
呢?谢谢你的关注,我会更新我的问题,所以它们是电子邮件地址。。。我猜是字符串还是字节。但是代码似乎无效。很好的评论。事实上,我比较的是ID,而不是电子邮件。您是否考虑添加电子邮件,因为这永远不会发生?确切地说,旧的
和新的
是什么?谢谢您的关注,我会更新我的问题,所以,它们是电子邮件地址。。。我猜是字符串还是字节。但是代码似乎无效。很好的评论。事实上,我比较的是ID,而不是电子邮件。你不打算添加电子邮件吗,因为这永远不会发生?我需要知道列表是否已更改。然后-1)选择已删除的电子邮件以通知他们-2)向新列表发送另一封不同的邮件。有关检查它们是否不同的信息,请参阅我的编辑。你的问题中没有提到第1)点和第2)点,是吗?你到底有什么问题
def diffs_loop2(a, b):
return [x for x in a if x in b], [x for x in b if x in a]
def diffs_np(a, b):
return np.setdiff1d(a, b, assume_unique=True), np.setdiff1d(b, a, assume_unique=True)
funcs = diffs_set, diffs_loop, diffs_loop2, diffs_np
for n in (10, 100, 1000, 10000):
print(n)
old_items = list(range(1, n))
new_items = list(range(n - 1))
for func in funcs:
print(func.__name__)
%timeit func(old_items, new_items)
print()
# 10
# diffs_set
# The slowest run took 4.52 times longer than the fastest. This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 914 ns per loop
# diffs_loop
# 1000000 loops, best of 3: 1.97 µs per loop
# diffs_loop2
# 100000 loops, best of 3: 2.09 µs per loop
# diffs_np
# 10000 loops, best of 3: 65.6 µs per loop
# 100
# diffs_set
# 100000 loops, best of 3: 5.23 µs per loop
# diffs_loop
# 100000 loops, best of 3: 13.6 µs per loop
# diffs_loop2
# 10000 loops, best of 3: 116 µs per loop
# diffs_np
# The slowest run took 5.74 times longer than the fastest. This could mean that an intermediate result is being cached.
# 10000 loops, best of 3: 65.9 µs per loop
# 1000
# diffs_set
# 10000 loops, best of 3: 57.7 µs per loop
# diffs_loop
# 10000 loops, best of 3: 132 µs per loop
# diffs_loop2
# 100 loops, best of 3: 10.7 ms per loop
# diffs_np
# 1000 loops, best of 3: 374 µs per loop
# 10000
# diffs_set
# 1000 loops, best of 3: 818 µs per loop
# diffs_loop
# 1000 loops, best of 3: 1.6 ms per loop
# diffs_loop2
# 1 loop, best of 3: 1.06 s per loop
# diffs_np
# 100 loops, best of 3: 3.5 ms per loop