python 高级进阶之找出多个字典中的公共键

python基础

浏览数:214

2019-8-25

In [1]: from random import randint, sample

# sample 是取样的意思,例如:sample('ABCDEF', 2) 会在'ABCDEF'这个字符串中随机抽取2个字符出来

In [2]: s1 = {x: randint(1,3) for x in sample('ABCDEF', randint(3, 6))}

In [3]: s2 = {x: randint(1,3) for x in sample('ABCDEF', randint(3, 6))}

In [4]: s3 = {x: randint(1,3) for x in sample('ABCDEF', randint(3, 6))}

In [5]: s1
Out[5]: {'A': 2, 'C': 3, 'D': 2, 'E': 3}

In [6]: s2
Out[6]: {'A': 3, 'B': 2, 'C': 3, 'D': 2, 'E': 2, 'F': 3}

In [7]: s3
Out[7]: {'B': 2, 'C': 3, 'D': 3, 'E': 2, 'F': 3}
  • 方法一:
    遍历
In [8]: res = []

In [9]: for x in s1:
   ....:     if x in s2 and x in s3:
   ....:         res.append(x)
   ....:

In [10]: res
Out[10]: ['C', 'E', 'D']
  • 方法二:
    集合与运算
In [11]: set(s1.keys()) & set(s2.keys()) & set(s3.keys())
Out[11]: {'C', 'D', 'E'}

In [12]: s1.viewkeys()
Out[12]: dict_keys(['A', 'C', 'E', 'D'])

# D.viewkeys() -> a set-like object providing a view on D's keys
# 返回该字典的一个 view 对象,类似数据库中的 view,当字典改变时,该 view 对象也跟着改变

In [13]: s1.viewkeys() & s2.viewkeys() & s3.viewkeys()
Out[13]: {'C', 'D', 'E'}
  • 方法三:
    map、reduce、与运算
In [14]: map(dict.viewkeys, [s1, s2, s3])
Out[14]:
[dict_keys(['A', 'C', 'E', 'D']),
 dict_keys(['A', 'C', 'B', 'E', 'D', 'F']),
 dict_keys(['C', 'B', 'E', 'D', 'F'])]

In [15]: reduce(lambda x, y: x&y, map(dict.viewkeys, [s1, s2, s3]))
Out[15]: {'C', 'D', 'E'}

补充说明:

map()
map(...)
    map(function, sequence[, sequence, ...]) -> list

    Return a list of the results of applying the function to the items of
    the argument sequence(s).  If more than one sequence is given, the
    function is called with an argument list consisting of the corresponding
    item of each sequence, substituting None for missing values when not all
    sequences have the same length.  If the function is None, return a list of
    the items of the sequence (or a list of tuples if more than one sequence).

map() 函数接收两个参数,一个是函数,一个是序列,map 将传入的函数依次作用到序列的每个元素,并把结果作为新的 list 返回。

def f(x):
    return x * x
map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])     # 结果: [1, 4, 9, 16, 25, 36, 49, 64, 81]

把数字转为字符串:

map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9])   # 结果: ['1', '2', '3', '4', '5', '6', '7', '8', '9']

只需要一行代码。

另外 map 也支持多个 sequence,这就要求 function 也支持相应数量的参数:

map(lambda x,y:x+y,[1,3],[2,4])     # 结果: [3, 7]
reduce()
reduce(...)
    reduce(function, sequence[, initial]) -> value

    Apply a function of two arguments cumulatively to the items of a sequence,
    from left to right, so as to reduce the sequence to a single value.
    For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
    ((((1+2)+3)+4)+5).  If initial is present, it is placed before the items
    of the sequence in the calculation, and serves as a default when the
    sequence is empty.

reduce 把一个函数作用在一个序列[x1, x2, x3…]上,这个函数必须接收两个参数,reduce 把结果继续和序列的下一个元素做累积计算,其效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

比方说对一个序列求和,就可以用 reduce 实现:

def add(x, y):
    return x + y

reduce(add, [1, 3, 5, 7, 9])    # 25

当然求和运算可以直接用 Python 内建函数 sum(),没必要动用 reduce

但是如果要把序列[1, 3, 5, 7, 9]变换成整数13579,reduce 就可以派上用场:

def fn(x, y):
    return x * 10 + y

reduce(fn, [1, 3, 5, 7, 9])     # 13579

这个例子本身没多大用处,但是,如果考虑到字符串 str 也是一个序列,对上面的例子稍加改动,配合 map(),我们就可以写出把 str 转换为 int 的函数:

def fn(x, y):
    return x * 10 + y

def char2num(s):
    return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]

reduce(fn, map(char2num, '13579'))      # 13579

整理成一个 str2int 的函数就是:

def str2int(s):
    def fn(x, y):
        return x * 10 + y
    def char2num(s):
        return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
    return reduce(fn, map(char2num, s))

还可以用 lambda 函数进一步简化成:

def char2num(s):
    return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]

def str2int(s):
    return reduce(lambda x,y: x*10+y, map(char2num, s))

也就是说,假设 Python 没有提供 int() 函数,你完全可以自己写一个把字符串转化为整数的函数,而且只需要几行代码!

作者:与蟒唯舞