比较列表和提取一些数据的最佳实践
Best practice to compare lists and extract some data
我有一个旧的电子邮件列表,应该更新为一个新的电子邮件列表。
我需要最有效的方法来比较它们和从旧列表中删除的select封电子邮件。
电子邮件列表存储在数据库中,因此我可以获得电子邮件 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@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)
这是一个好习惯吗?或者最好使用 for loop
?为什么?
您可以使用列表理解。正如你所说,电子邮件本身是独一无二的,我不确定你想用这些 ID 做什么,我们不需要转换成集合(如果我弄错了请纠正我)。
deleted = [email for email in old_emails_list if email not in new_emails_list]
恕我直言,这种方法的优点是可读性好,不需要外部包。
编辑
检查新列表是否与旧列表不同,有两种情况:
a) 如果已知新列表是旧列表的子列表,只需检查deleted
中是否有任何元素,如上计算。
b) 如果新列表中可能有新邮件,检查deleted
是否包含任何邮件,如果没有,另外检查是否len(new_emails_list)==len(old_emails_list)
。
首先,在if
条件下你已经在努力工作了,所以没有太多需要事先测试。
其次,不清楚你的起点是什么,如果是ID或电子邮件或两者之一,你的终点是什么。
但似乎最干净的方法是一直使用 set
。
我假设您对 ID 没问题(但同样的代码也适用于电子邮件地址):
n = 3
a = set(range(1, n)) # *old* items
b = set(range(n - 1)) # *new* items
c = a - b # items present in b but not in a (added)
# {0}
d = b - a # items present in a but not in b (deleted)
# {2}
现在,让我们假设起点是两个 list
(同样,ID 或电子邮件是无关紧要的,为了简单起见,我只假设 ID),并且让我们假设您想知道添加和删除的项目。有几种可能的方法:
def diffs_set(a, b):
a = set(a)
b = set(b)
return a - b, b - a
def diffs_loop(a, b):
a = set(a)
b = set(b)
return [x for x in a if x in b], [x for x in b if x in a]
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
最重要的一点是,通过使用集合,可以获得最快和最干净的方法。
需要注意的是 set
甚至对于 list
理解也是有用的,因为 if
条件变为 O(1)
(导致整体 O(n)
) O(n)
(导致总体 O(n²)
)。
因为最昂贵的操作是在开始时实际构建 set
,所以如果只需要 a - b
或 b - a
,列表理解可能会比仅使用集合更有竞争力,因为那么只需要一个 set()
调用。
相反,基于 NumPy 的方法在这里没有竞争力。
我有一个旧的电子邮件列表,应该更新为一个新的电子邮件列表。
我需要最有效的方法来比较它们和从旧列表中删除的select封电子邮件。
电子邮件列表存储在数据库中,因此我可以获得电子邮件 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@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)
这是一个好习惯吗?或者最好使用 for loop
?为什么?
您可以使用列表理解。正如你所说,电子邮件本身是独一无二的,我不确定你想用这些 ID 做什么,我们不需要转换成集合(如果我弄错了请纠正我)。
deleted = [email for email in old_emails_list if email not in new_emails_list]
恕我直言,这种方法的优点是可读性好,不需要外部包。
编辑
检查新列表是否与旧列表不同,有两种情况:
a) 如果已知新列表是旧列表的子列表,只需检查deleted
中是否有任何元素,如上计算。
b) 如果新列表中可能有新邮件,检查deleted
是否包含任何邮件,如果没有,另外检查是否len(new_emails_list)==len(old_emails_list)
。
首先,在if
条件下你已经在努力工作了,所以没有太多需要事先测试。
其次,不清楚你的起点是什么,如果是ID或电子邮件或两者之一,你的终点是什么。
但似乎最干净的方法是一直使用 set
。
我假设您对 ID 没问题(但同样的代码也适用于电子邮件地址):
n = 3
a = set(range(1, n)) # *old* items
b = set(range(n - 1)) # *new* items
c = a - b # items present in b but not in a (added)
# {0}
d = b - a # items present in a but not in b (deleted)
# {2}
现在,让我们假设起点是两个 list
(同样,ID 或电子邮件是无关紧要的,为了简单起见,我只假设 ID),并且让我们假设您想知道添加和删除的项目。有几种可能的方法:
def diffs_set(a, b):
a = set(a)
b = set(b)
return a - b, b - a
def diffs_loop(a, b):
a = set(a)
b = set(b)
return [x for x in a if x in b], [x for x in b if x in a]
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
最重要的一点是,通过使用集合,可以获得最快和最干净的方法。
需要注意的是 set
甚至对于 list
理解也是有用的,因为 if
条件变为 O(1)
(导致整体 O(n)
) O(n)
(导致总体 O(n²)
)。
因为最昂贵的操作是在开始时实际构建 set
,所以如果只需要 a - b
或 b - a
,列表理解可能会比仅使用集合更有竞争力,因为那么只需要一个 set()
调用。
相反,基于 NumPy 的方法在这里没有竞争力。