在Python中计算一个列表中元素在另一个列表中出现的次数。

5
a = list([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])
b = list([1, 3, 6, 9])

我该如何计算列表a中某一项在列表b中出现的次数?

上面的示例应该返回值为4。

在撰写这个问题时,我想到了下面的方法(似乎可行)

a = list([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])
b = list([1, 3, 6, 9])
c = 0
for n in b:
    if n in a:
        c += 1
        continue
print (c)

但是可能有更简便的方法,可以使用列表比较或其他方法吗?


1
“b”保证是唯一值吗?因为你可以这样做:len(set(b).intersection(a)) - Jon Clements
你不需要在所有的列表周围都加上 list 调用。 - user2357112
你想要统计特定项出现的次数吗?例如,列表a中1出现了多少次。或者你想要统计两个列表中有多少相同的项吗? - Uli Sotschok
@Jon Clements - 在这种情况下,两个列表都是唯一的。 - Escribblings
@user2357112 - 谢谢,我对Python非常新手。 - Escribblings
显示剩余3条评论
7个回答

8
您可以使用内置的 sum 函数:
sum(i in b for i in a)

输出:

4

1
为什么这个被踩了?目前还不可能知道OP拥有的确切数据。 - roganjosh

3

如果您只想计算两个列表中共同元素的数量(而且您不需要知道它们在另一个列表中出现的次数),则可以直接使用:

count = len(set(a).intersection(set(b)))

或者等同于:

count = len(set(a) & set(b))

3

这个问题和你链接的那个问题的区别在于,我不想返回匹配的值,我只需要计算有多少个。 - Escribblings
当然。我只是说比较列表(无论您是否可以计数)是一个老问题 :) 希望我能帮到你。 - Juan Antonio
1
谢谢。我对 Python 还很陌生,有时很难从众多的示例代码中找到与我正在尝试的不同的内容。 - Escribblings
1
好的,我已经接受了你和@Chris上面的答案作为我的问题的解决方案。我会支付两个答案来看哪个更适合我。谢谢。 - Escribblings
这与我的答案完全相同。 - ruohola

2

试试这个只需要一行代码:

最初的回答:

s = sum(a.count(i) for i in b if i in a)

s 的输出将会是 4。 此外,它支持在 a 中存在重复项。


1
这是不必要的低效率,因为您在每次迭代中都在计算相同的计数。 - yatu

2
以下是几种变化,可以计算重复项并忽略b中没有的所有值。"
from collections import Counter
# a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
a = [1, 4, 3, 1, 2, 4, 4, 5, 6, 6, 7, 7, 7, 7, 8, 9, 0, 1]
b = [1, 3, 6, 9]

counts = Counter()
# make counts order match b order
for item in b:
    counts[item] = 0
for item in a:
    if item in b:
        counts[item] += 1
print("in 'b' order")
print([(k, v) for k, v in counts.items()])
print("in descending frequency order")
print(counts.most_common())
print("count all occurrences in a of elements that are also in b")
print(sum(counts.values()))



python count_b_in_a.py
in 'b' order
[(1, 3), (3, 1), (6, 2), (9, 1)]
in descending frequency order
[(1, 3), (6, 2), (3, 1), (9, 1)]
count all occurrences in a of elements that are also in b
7

针对您关于性能的评论,以下是Python中扫描列表和扫描集合的比较:

最初的回答:

import datetime

def timestamp():
    return datetime.datetime.now()


def time_since(t):
    return (timestamp() - t).microseconds // 1000


a = list(range(1000_000))
b = set(a)
iterations = 10
t = timestamp()
for i in range(iterations):
    c = 974_152 in a
print("Finished {iterations} iterations of list scan in {duration}ms"
      .format(iterations=iterations, duration=time_since(t)))
t = timestamp()
for i in range(iterations):
    c = 974_152 in b
print("Finished {iterations} iterations of set scan in {duration}ms"
      .format(iterations=iterations, duration=time_since(t)))

python scan.py
Finished 10 iterations of list scan in 248ms
Finished 10 iterations of set scan in 0ms

第一点要注意:Python在这方面也不慢。在旧笔记本电脑上扫描1000万个列表元素只需要1/4秒,这已经很不错了。但它仍然是一个线性扫描。
Python集合类别不同。如果你从time_since()中去掉// 1000,你会发现Python在不到一微秒的时间内10次扫描了一个100万成员的集合。你会发现其他集合操作也非常快速。无论何时使用Python中的集合,都要使用它们:它们非常棒。
如果你正在考虑将上述代码应用于更大的列表,其中性能很重要,第一件事可能是将b转换为一个集合。

谢谢,但这比我用过的代码多得多,它更有效吗? - Escribblings
这是更多的代码,因为它给了你更多的选项。Counter非常快。如果你只对在a中每个项目的存在或缺失感兴趣,则set()操作是最快的。由于这是Python,如果您想要超级高效,则来错地方了。坦率地说,我发现效率很少是Python的问题。总体而言,Python文化更关注清晰、简单、易于维护的代码,而不是最佳性能。 - Nic
好的,谢谢您的回复。 - Escribblings

1
这个一行代码也应该能行。找到每个元素的数量并将这些数量相加。
op = sum([a.count(j) for j in b])

"

输出将是

"
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
b = [1, 3, 6, 9]
#4
a = [1, 1, 2, 3, 3, 3, 4, 5, 6, 6 , 7, 8, 9, 0]
b = [1, 3, 6, 9]
#8


这似乎与上面@Mehrdad Pedramfar的答案相似,被指责效率低下。不过我不太清楚是否是这种情况。 - Escribblings

0

虽然 set 可以用于去重

但列表推导式也会考虑重复元素

a = [1,1]
b = [1,1]

count = len(set(a) & set(b)) 
count2 = sum(i in b for i in a)  
print(count, count2) 

1 2

[Program finished] 

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