从列表中的子列表中查找公共元素
find common elements from sublist in list
我有两个列表,我必须从第一个列表中提取项目,第一个元素出现在第二个列表中。我粘贴在下面的代码运行良好,但由于我要处理数百万条记录,所以速度非常慢。有人知道如何优化它吗?
a = [[1,0],[2,0],[3,0],[4,0]]
b = [2,4,7,8]
same_nums = list(set([x[0] for x in a]).intersection(set(b)))
result = []
for i in a:
if i[0] in same_nums:
result.append(i)
print(result)
尝试使用过滤器来理解列表,而不是创建第二个具有相同大小的列表并通过集合,例如:
[x for x in a if x[0] in b]
可能会更快。
在您发布的代码中,您做了很多事情:创建一个删除第二维的副本,从中创建一个集合,将其与另一个集合相交,然后将该集合复制回列表.大名单至少这样处理了四次。我的提案只通过列表一次,所以我实际上希望它更快。
你把事情复杂化了。只需将 b
变成 set
即可加快包含检查。那么推导式中 a
的一次迭代就足够了:
set_b = set(b) # makes vvvvvvvvvvvvv O(1)
result = [x for x in a if x[0] in set_b]
特别是将 same_nums
变回 list
是真正的性能杀手,因为它使整个事情再次 O(m*n)
。 b
中的一组是 O(m+n)
。但是 same_nums
一开始是完全没有必要的,因为你知道所有 i[0]
都在 a
中,因为你正在迭代 a
.
我推荐使用 Numpy 库,因为它在后台使用 C/C++ 实现,因此运行速度更快。
import numpy as np
a = np.random.randint(10000, size=(10000000, 2))
b = np.random.randint(10000, size=1000)
mask = np.isin(a[:,0], b)
a_masked = a[mask, :]
# Exec time: 3.2 s ± 185 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
另一种方法(Python 列表)相同数量元素的执行时间如下:
[x for x in a if x[0] in b]
# Exec time: 55.1 s ± 5.47 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
如您所见,numpy
运行得更快。您还可以将 python 列表转换为 numpy,反之亦然 simply.
a = [[1,0],[2,0],[3,0],[4,0]]
b = [2,4,7,8]
def return_common_elemens(a,b):
for subval in a:
if subval[0] in b:
yield subval
print(list(return_common_elemens(a,b)))
>>>[[2, 0], [4, 0]]
最佳解决方案(至少我的具体情况)是由 schwobaseggl 和 Novin Shahroudi
提供的
我目前正在使用 schwobaseggl 的建议,因为我正在从 SQL 查询中读取数据,而 Novin Shahroudi 解决方案要求我进行更多数据类型转换。
我有两个列表,我必须从第一个列表中提取项目,第一个元素出现在第二个列表中。我粘贴在下面的代码运行良好,但由于我要处理数百万条记录,所以速度非常慢。有人知道如何优化它吗?
a = [[1,0],[2,0],[3,0],[4,0]]
b = [2,4,7,8]
same_nums = list(set([x[0] for x in a]).intersection(set(b)))
result = []
for i in a:
if i[0] in same_nums:
result.append(i)
print(result)
尝试使用过滤器来理解列表,而不是创建第二个具有相同大小的列表并通过集合,例如:
[x for x in a if x[0] in b]
可能会更快。
在您发布的代码中,您做了很多事情:创建一个删除第二维的副本,从中创建一个集合,将其与另一个集合相交,然后将该集合复制回列表.大名单至少这样处理了四次。我的提案只通过列表一次,所以我实际上希望它更快。
你把事情复杂化了。只需将 b
变成 set
即可加快包含检查。那么推导式中 a
的一次迭代就足够了:
set_b = set(b) # makes vvvvvvvvvvvvv O(1)
result = [x for x in a if x[0] in set_b]
特别是将 same_nums
变回 list
是真正的性能杀手,因为它使整个事情再次 O(m*n)
。 b
中的一组是 O(m+n)
。但是 same_nums
一开始是完全没有必要的,因为你知道所有 i[0]
都在 a
中,因为你正在迭代 a
.
我推荐使用 Numpy 库,因为它在后台使用 C/C++ 实现,因此运行速度更快。
import numpy as np
a = np.random.randint(10000, size=(10000000, 2))
b = np.random.randint(10000, size=1000)
mask = np.isin(a[:,0], b)
a_masked = a[mask, :]
# Exec time: 3.2 s ± 185 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
另一种方法(Python 列表)相同数量元素的执行时间如下:
[x for x in a if x[0] in b]
# Exec time: 55.1 s ± 5.47 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
如您所见,numpy
运行得更快。您还可以将 python 列表转换为 numpy,反之亦然 simply.
a = [[1,0],[2,0],[3,0],[4,0]]
b = [2,4,7,8]
def return_common_elemens(a,b):
for subval in a:
if subval[0] in b:
yield subval
print(list(return_common_elemens(a,b)))
>>>[[2, 0], [4, 0]]
最佳解决方案(至少我的具体情况)是由 schwobaseggl 和 Novin Shahroudi
提供的我目前正在使用 schwobaseggl 的建议,因为我正在从 SQL 查询中读取数据,而 Novin Shahroudi 解决方案要求我进行更多数据类型转换。