代码之家  ›  专栏  ›  技术社区  ›  void.pointer

在python中,如何合并具有相似键的dictionary元素?

  •  0
  • void.pointer  · 技术社区  · 6 年前

    在吉特,我跑 git shortlog -sn 在回购中建立作者及其承诺的列表。在某些情况下,多个作者实际上是同一个人,但大小写或名字不同,而不是姓+名。例子:

    $ git shortlog -sn
    100 John Doe
     50 john
    

    使用 subprocess

    >>> users = {"John Doe": 100, "john": 50}
    >>> users
    {'John Doe': 100, 'john': 50}
    

    我需要遍历这些,并在键上运行regex,比较两个名称是否以相同的名字开头(不考虑大小写),以及:

    1. 组合键以显示不同的作者名称
    2. 对每个元素的提交(值)求和。所以最终结果应该是:

      {'John Doe, john': 150}
      

    2 回复  |  直到 6 年前
        1
  •  0
  •   fl00r    6 年前

    一个简单的解决方案是这样的

    data = {"John Doe": 100, "john": 50}
    new_data = {}
    for name, amount in data.items():
        first_name = name.lower().split(" ")[0]
        (current_names, current_amount) = new_data.get(first_name, [[], 0])
        current_names.append(name)
        current_amount += amount
        new_data[first_name] = [current_names, current_amount]
    
    new_data
    #=> {'john': [['john', 'John Doe'], 150]}
    
    names_and_data = {}
    for names, amount in new_data.values():
        joined_names = ", ".join(names)
        names_and_data[joined_names] = amount
    
    names_and_data
    #=> {'john, John Doe': 150}
    
        2
  •  0
  •   Alexander McFarlane    6 年前

    代码段

    from collections import defaultdict
    
    dd = defaultdict(list)
    for u in users:
        k = u.split()[0].lower()
        dd[k].append(u)
    
    merged = {','.join(names): sum(users[name] for name in names)
              for firstname, names in dd.items()}
    

    解释

    In [184]: from collections import defaultdict
    
    In [185]: dd = defaultdict(list)
    
    In [186]: for u in users:
         ...:     k = u.split()[0].lower()
         ...:     dd[k].append(u)
         ...:
    
    In [187]: dd
    Out[187]: defaultdict(list, {'john': ['john', 'John Doe']})
    

    然后可以使用此查找表创建合并格式,如下所示

    In [188]: merged = {','.join(names): sum(users[name] for name in names)
        ...:            for firstname, names in dd.items()}
    
    In [189]: merged
    Out[189]: {'john,John Doe': 150}
    

    join

    In [188]: merged = {', '.join(names): sum(users[name] for name in names)
        ...:            for firstname, names in dd.items()}
    
    In [189]: merged
    Out[189]: {'john, John Doe': 150}
    

    请注意,这不会区分

    jonathan
    john
    jon
    jon-dawg
    

    正如@wim所建议的,这是一个需要一些自定义正则表达式的复杂得多的问题