如何获取列表的共同元素数量

0 投票
3 回答
940 浏览
提问于 2025-04-17 14:03

这里有一个字典,里面包含了很多列表,比如:

  list_dic= {
    q1:[1,2,3,4,5]
    q2:[2,3,5]
    q3:[2,5]
    }

我想要找出每个列表中共同的元素数量,比如说,q1和q2的共同元素数量是3,具体是(2,3,5)。

q1={q2:3, q3:2}
q2={q1:3,q3:2}
q3={q1:2, q2:2}

我为这个任务写的代码是:

result = {}
for name, source_list in list_dic.items():
    for target_name, target_list in list_dic.items():
        count = 0
        for item in source_list:
            if item in target_list:
                count+=1
    result[name][target_name] = count 

但是这个算法效率不高,我想知道有没有更好的算法来完成这个任务。

3 个回答

0

如果你不在意列表里能不能有重复的数字,你可以用set()这种类型来实现。

>>> s1 = set([1,2,3,4,5])
>>> s2 = set([3,4,5,6,7,8])
>>> s1 & s2
{3, 4, 5}
3

在编程中,有时候我们需要让程序做一些事情,比如在特定的条件下执行某些代码。这就像给程序设定了一些规则,只有当这些规则满足时,程序才会按照我们的要求去做。

例如,如果你想让程序在用户输入的数字大于10时显示一条消息,你就需要用到条件语句。条件语句就像是一个检查点,程序会在这里停下来,看看条件是否成立。如果成立,程序就会执行你设定的代码;如果不成立,程序就会跳过这些代码,继续执行后面的内容。

这样做的好处是,程序可以根据不同的情况做出不同的反应,让它变得更加灵活和智能。

from collections import defaultdict
#Create a default dict. You don;t have to handle KeyError condition
result = defaultdict(dict)
list_dic= {
    'q1':[1,2,3,4,5],
    'q2':[2,3,5],
    'q3':[2,5],
    }
#Convert the value list to set list
set_dict = {k:set(v) for k,v in list_dic.items()}
# For both way mapping, you need permutation i.e. (q1, q2) and (q2, q1)
for k1, k2 in permutations(set_dict.keys(),2):
    # Now `&` is Set Intersection. The Len will return the length of the common elements
    result[k1][k2] = len(set_dict[k1] & set_dict[k2])


result
defaultdict(<type 'dict'>, {'q1': {'q3': 2, 'q2': 3}, 'q3': {'q1': 2, 'q2': 2}, 'q2': {'q1': 3, 'q3': 2}})
3

我觉得这样做就可以了:

import itertools
import collections

q1 = 'q1'
q2 = 'q2'
q3 = 'q3'

dic_list = {
     q1:[1,2,3,4,5],
     q2:[2,3,5],
     q3:[2,5]
     }

#sets are much more efficient for this sort of thing.  Create a dict
#of the same structure as the old one, only with `set` as values 
#instead of `list`
dic_set = {k:set(v) for k,v in dic_list.items()}

new_dic = collections.defaultdict(dict)
for k1,k2 in itertools.combinations(dic_set,2):
     #to get the count, we just need to know the size of the intersection
     #of the 2 sets.
     value = len(dic_set[k1] & dic_set[k2]) 
     new_dic[k1][k2] = value
     new_dic[k2][k1] = value

print (new_dic)

如果你看评论的话,会发现 combinationspermutations 稍微快一点:

import itertools
import collections

q1 = 'q1'
q2 = 'q2'
q3 = 'q3'


dic_list = {
     q1:[1,2,3,4,5],
     q2:[2,3,5],
     q3:[2,5]
     }

dic_set = {k:set(v) for k,v in dic_list.items()}

def combo_solution():
     new_dic = collections.defaultdict(dict)
     for k1,k2 in itertools.combinations(dic_set,2):
          value = len(dic_set[k1] & dic_set[k2])
          new_dic[k1][k2] = value
          new_dic[k1][k2] = value
     return new_dic

def perm_solution():
     new_dic = collections.defaultdict(dict)
     for k1, k2 in itertools.permutations(dic_set,2):
          new_dic[k1][k2] = len(dic_set[k1] & dic_set[k2])
     return new_dic

import timeit
print timeit.timeit('combo_solution()','from __main__ import combo_solution',number=100000)
print timeit.timeit('perm_solution()','from __main__ import perm_solution',number=100000)

结果是这样的:

0.58366894722    #combinations
0.832300901413   #permutations

这是因为 set.intersection 的操作复杂度是 O(min(N,M))——这个操作本身不贵,但如果你做的次数是需要的两倍,那就会累积起来变得比较慢。

撰写回答