• 字典对象相加


    SO上看到一个比较好的问题.大概是:

    For example I have two dicts:

    Dict A:{'a':1,'b':2,'c':3}

    Dict B:{'b':3,'c':4,'d':5}

    I need a pythonic way of 'combining' two dicts such that the result is :

    {'a':1,'b':5,'c':7,'d':5}

    That is to say: if a key appears in both dicts, add their values, if it appears in only one dict, keep its value.

    我发现有3类答案,每一个都有值得学习的地方.

    (1)首先来一个比较酷的解法:

    a = {'a': 'foo', 'b':'bar', 'c': 'baz'}
    b = {'a': 'spam', 'c':'ham', 'x': 'blah'}
    
    r = dict(a.items() + b.items() +
        [(k, a[k] + b[k]) for k in set(b) & set(a)])

    这里面用到了一个难以觉察到的设置,举例说明:

    >>> dict([(1,2),(1,2),(1,3),(2,3),(2,4)])
    {1: 3, 2: 4}

    可以看到,在将列表转换为字典的过程中,如果出现了相同的键,那么Python是默认取最后一个键及其对应的值.

    另外,set的用法也显得非常简练.作者后来还给出了更普遍的版本:

    def combine_dicts(a, b, op=None):
        op = op or (lambda x, y: x + y)
        return dict(a.items() + b.items() +
            [(k, op(a[k], b[k])) for k in set(b) & set(a)])

    我才知道OR运算符不是仅仅返回True或False的...

    >>> a= None or 2
    >>> a
    2
    >>> 4 or 2
    4
    >>> not None or 2
    True
    >>>

    这位作者曾经解答过我一个遍历树的问题,我花了一天时间冥思苦想,最后在递归和生成器的理解上进步一大截.

    这是他SO主页:http://stackoverflow.com/users/989121/thg435

    (2)下面来一个面向对象风格的:

    class MyDict(dict):
        def __add__(self, oth):
            r = self.copy()
            for key, val in oth.items():
                if key in r:
                    r[key] += val # You can custom it here
                else:
                    r[key] = val
            return r
    
    a = MyDict({'a':1, 'b':2, 'c':3})
    b = MyDict({'b':3, 'c':4, 'd':5})
    
    print a+b # Output {'a':1, 'b': 5, 'c': 7, 'd': 5}

    原来__add__方法是这么来的.同时我也觉得,面向对象编程还是挺不错的,继承,撰写特殊方法,很方便的嘛.

    另外,字典的copy方法原来就是在这种地方起作用的--很方便地返回一个和原字典内容一样的新的字典对象.毕竟2个字典相加后返回的新字典一般都是要求具有独立性的.

    以前我一直想不通这个方法是拿来干嘛的..现在是明白一些了.

    题外话:出于对copy一贯的警觉,我对字典的copy方法进行了一些测试,发现还是一贯地"陷阱".并非那么独立..

    >>> d={1: [], 2: 4}
    >>> e=d.copy()
    >>> e
    {1: [], 2: 4}
    >>> e[1].append('trap?')
    >>> d
    {1: ['trap?'], 2: 4}

    可见,当字典的值是可变对象时(比如list),copy是返回一个引用,并非新对象.总之,如果你的字典值包含可变对象,为了确保不发生"惊喜",还是用copy.deepcopy吧:

    >>> import copy
    >>> e=copy.deepcopy(d)
    >>> e
    {1: ['trap?'], 2: 4}
    >>> e[1].append('no_trap')
    >>> d
    {1: ['trap?'], 2: 4}
    >>> 

    (3)最后是典型的Python风格--找现成轮子,import搞定之:

    >>> from collections import Counter
    >>> A = Counter({'a':1, 'b':2, 'c':3})
    >>> B = Counter({'b':3, 'c':4, 'd':5})
    >>> A + B
    Counter({'c': 7, 'b': 5, 'd': 5, 'a': 1})

    目前发现Python有以下一些基础库,提供一些不牵扯具体应用的有用的函数:

    collections
    functools
    operator
    itertools
  • 相关阅读:
    C++每次读取一行字符串输入(学习笔记) (转)
    Ubuntu使用Windows下的conio.h
    容斥原理、欧拉函数、phi
    UVa1635
    转:用STL中的vector动态开辟二维数组
    [转载]Vector用法(C++ Primer中文版)
    c++中vector的pair与make_pair的使用,双关键字排序
    uva12716 GCD XOR
    在 Ubuntu 14.04 中安装 Pepper Flash Player For Chromium
    Careercup
  • 原文地址:https://www.cnblogs.com/xiangnan/p/3393153.html
Copyright © 2020-2023  润新知