Python:计算两个大数组中元素的出现次数

3
我有以下脚本,用于将一个数组中的值计数到另一个数组中。
array_1 = [1,2,0,5,7,0]
array_2 = [1,0,1,1,9,6]
# on array 2 there are 3 occurrence of 1, and 1 occurrence of zero, but because there is another zero at array_1 add 1 more. 3+2 = 5

for r in array_1:
     total_count = total_count + array_2.count(r)

print("total sum: {0}".format(total_count))

当处理小数组大小时,它很好用,但是当数组大小增加时(array_1array_2都为100万),就会遇到困难。有更好的方法来解决吗?

抱歉造成困扰,我稍微更新了一下问题。


为什么array2没有1个9的出现?因为9不在array1中? - Patrick Artner
我需要使用数组1来计算数组2中重复出现的数字数量。 - Led
不要采用我的解决方案,使用Netwave的解决方案。 - MegaIng
4个回答

5

注意:@Netwave的答案快五倍。

你可以使用collections.Counter。它会更快,因为它只迭代一次列表。

from collections import Counter

array_1 = [1,2,0,5,7]
array_2 = [1,0,1,1,9]

c = Counter(array_1)
total_count = sum(c[x] for x in array_2)

print("total sum: {0}".format(total_count))

1
我想补充一点,循环中调用 count 需要对列表进行单独的遍历以进行每个 count 调用,这就是为什么 collections.Counter 更快的原因。 - scharette
@Megalng,是的,他的答案更快,但我有大量的数组,你的结果是正确的。 - Led

2

使用set而不是列表:

array1_set = set(array_1)
total_count = sum(1 for x in array_2 if x in array1_set)

我需要重新计算甚至是重复的内容。 - Led
它确实可以,但结果与我需要的不同。 - Led
@Led,你是指array_1中的重复项吗? - Netwave
@Led 我不认为你理解“正确”一词的含义。结果与你的需求有何不同? - Aran-Fey
是的,重复项必须在数组1和数组2中重新计算。 - Led

1
如果数组1中有很多重复的数字,通过缓存它们(构建一个形如{number: count}的字典)可以节省时间。一个典型的缓存函数如下所示:
counts = {}
def get_count(number):
    if number in counts:
        return counts[number]
    else:
        count = your_counting_function(number)
        counts[number] = count
        return count

这种行为被打包成functools.lru_cache装饰器,因此函数可以简化为:

from functools import lru_cache

@lru_cache(maxsize=None)
def get_count(number):
    return array_2.count(number)

如果你的数组1中有一小组不同的值,比如数字1到10的随机洗牌,那么这将是一个相当高效的方法。有时人们会称数组1具有低基数(基数为10)。

如果你的数组1中有很多不同的值(例如,在100万个值的数组中有90万个不同的值),更好的优化方法是在开始之前预先计算所有的计数,这样你只需要对数组2进行一次遍历。字典查找比整个数组的计数要快得多得多。

array_2_counts = {}
for number in array_2:
    if number in counts:
        array_2_counts[number] += 1
    else:
        array_2_counts[number] = 1


total_count = 0
for number in array_1:
    total_count += array_2_counts[number]

Python也内置了相应的功能!可以使用collections.Counter简化上述代码:

from collections import Counter

array_2_counter = new Counter(array_2)
for number in array_1:
    total_count += array_2_counter[number]

谢谢您的解释,但我会选择Megalng的答案,因为他/她先发布了。谢谢。 - Led

0
array_1 = [1,2,0,5,7]
array_2 = [1,0,1,1,9]
array_2_counts = {}
for number in array_1:
 freq=array_2.count(number)
 array_2_counts.update({number:freq})
print(array_2_counts)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接