在python中找到给出N个字典的唯一(键:值)对

Kru*_*pös 4 python algorithm dictionary python-3.x

我想找到一种简单和/或快速的方法来查找在python中给出N个字典的所有普通情侣(对:值).(3.X会是最好的)

问题

给定一组3 dicts(但它可以是任何一个dict,它仅用于示例)

n1 = {'a': 1, 'b': 2, 'c': 3}
n2 = {'a': 1, 'b': 4, 'c': 3, 'd': 4}
n3 = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
Run Code Online (Sandbox Code Playgroud)

共同结果(键:值)n1,n2n3 应该是:

({'a': 1, 'c': 3})
Run Code Online (Sandbox Code Playgroud)

而对于n2n3它应该是

({'a': 1, 'c': 3, 'd': 4})
Run Code Online (Sandbox Code Playgroud)

我首先考虑使用强力算法来检查每个字典的每一对(键:值)

这是使用递归算法的实现

解决方案A.

list_dict = [n1, n2, n3]

def finding_uniquness(ls):

    def recursion(ls, result):
        if not ls:
            return result
        result = {k: v  for k, v in result.items()  for k1, v1 in ls[0].items() if k == k1 and v == v1}
        return recursion(ls[1:], result)

    return recursion(ls[1:], ls[0])


finding_uniquness(list_dict)
# {'c': 3, 'a': 1}
Run Code Online (Sandbox Code Playgroud)

但它不容易理解,而且复杂性很高(我不确定如何计算复杂性;但是由于我们比较了所有元素dict,复杂性应该是O(N²)?)

然后,我虽然Sets.因为它可以自然地比较所有元素

解决方案B.

import functools

list_dict = [n1, n2, n3]
set_list = [set(n.items()) for n in list_dict]

functools.reduce(lambda x, y: x & y, set_list)
 # {('a', 1), ('c', 3)}
Run Code Online (Sandbox Code Playgroud)

它比以前的解决方案好得多,不幸的是,当其中一个key具有listas值时会抛出错误:

>>> n = {'a': [], 'b': 2, 'c': 3}
>>> set(n.items()) 
Run Code Online (Sandbox Code Playgroud)

TypeError:不可用类型:'list'

我的问题是双重的:

  • 有没有比解决方案A更好的算法?
  • 或者有没有办法避免TypeError使用解决方案B

当然,欢迎任何其他言论.

Ste*_*ann 7

更简单,更有效的方式:

>>> {k: v
     for k, v in list_dict[0].items()
     if all(k in d and d[k] == v
            for d in list_dict[1:])}
{'c': 3, 'a': 1}
Run Code Online (Sandbox Code Playgroud)

使用额外的变量list_dict[1:]可能是有益的,否则短路会all有些浪费.或者,如果您之后不需要列表,则可以弹出"主"字典:

>>> {k: v
     for k, v in list_dict.pop().items()
     if all(k in d and d[k] == v
            for d in list_dict)}
{'c': 3, 'a': 1}
Run Code Online (Sandbox Code Playgroud)

或使用get@ Jean-FrançoisFabre建议的不能在字典中的默认值:

>>> marker = object()
>>> {k: v
         for k, v in list_dict.pop().items()
         if all(d.get(k, marker) == v
                for d in list_dict)}
{'c': 3, 'a': 1}
Run Code Online (Sandbox Code Playgroud)