我想找到一种更有效的方法从一组数组中查找共同值。假设我有三个数组列表:
list_1 = [np.array([1, 2, 3]), np.array([]), np.array([4, 5, 6])]
list_2 = [np.array([2, 3, 6], np.array([1, 2, 3]), np.array([4, 5, 6, 7, 8, 9])]
list_3 = [np.array([5, 2, 3, 7]), np.array([7, 8, 9]), np.array([1, 2, 3, 4, 5, 6])]
我想要得到的是每个索引中公共元素数组的另一个列表:
out = [np.array([2, 3]), np.array([]), np.array([4, 5, 6])]
目前我正在使用:
common_vals = []
for index in range(len(list_1)):
common_elements = reduce(np.intersect1d, (list_1[index], list_2[index], list_3[index])
common_vals.append(common_elements)
当list_1的长度可以是几千个项目并且列表的数量很大时,这非常慢。
可以通过以下方式创建测试集:
from random import random
list_1, list_2, list_3 = [], [], []
for i in range(10_000):
length_1 = random.randint(0, 1000)
list_1.append(np.array([random.randint(0,1000) for _ in range(length_1)]))
length_2 = random.randint(0, 1000)
list_2.append(np.array([random.randint(0,1000) for _ in range(length_2)]))
length_3 = random.randint(0, 1000)
list_3.append(np.array([random.randint(0,1000) for _ in range(length_3)]))
[澄清]
数组列表是索引列表,因此数字始终是整数。它们是有序的并且需要保持该顺序并且将始终具有相同的长度。因此,公共项输出的第一个列表应该是每个输入列表的索引 1 中的公共项。输入列表中的每个项目都是唯一的,因此在最终输出列表中它们应该出现一次。
我怀疑 numpy 在这里会有多大帮助。在我看来,最简单的方法是使用 Python 的集合。转置列表列表以获得列列表,将每列的元素转换为集合,并对它们运行
set.intersection
。
lists = [list_1, list_2, list_3]
intersections = [set.intersection(*[set(x) for x in col]) for col in zip(*lists)]
print(intersections)
# => [{2, 3}, set(), {4, 5, 6}]
使用
set
intersection
怎么样?:
[set.intersection(*map(set, x)) for x in zip(list_1, list_2, list_3)]
输出:
[{2, 3}, set(), {4, 5, 6}]
(使用更大的测试集)
# numpy
1.92 s ± 113 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# set intersection
801 ms ± 104 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
我从您的一条评论中意识到您希望保留商品的原始顺序。
您可以调整上面的代码以首先获取一组,然后使用它来过滤其中一个列表(例如第一个):
def ordered_intersection(it):
S = set.intersection(*map(set, it))
return [x for x in it[0] if x in S]
out = [ordered_intersection(x) for x in zip(list_1, list_2, list_3)]
输出:
[[2, 3], [], [4, 5, 6]]