寻找更优雅(更少代码)的方式来比较多个dicts

时间:2017-12-18 22:31:19

标签: python python-3.x compare

前一段时间我问了一个关于比较2个dicts的问题,以便检测相同的密钥并保持重复的最高值。 这个社区带来了一个解决方案,它允许我将2个dicts与彼此进行比较,并将它的最高值存储在一个新的dict中,如果需要,我可以将其与另一个dict进行比较。

但随着dicts的数量越来越多,代码本身也越来越大。

for key in dict1:
    if key not in dict2 or dict1[key] > dict2[key]:
        dict2[key] = dict1[key]
dict2a = {**dict1, **dict2}

for key in dict2a:
    if key not in dict3 or dict2a[key] > dict3[key]:
         dict3[key] = dict2a[key]
dict3a = {**dict2a, **dict3}

for key in dict3a:
    if key not in dict4 or dict3a[key] > dict4[key]:
        dict4[key] = dict3a[key]
dict4a = {**dict3a, **dict4}

我试图想出一个能够遍历所有这些决定的解决方案。 这个问题也与另一个问题挂钩,但为了保持解决方案的分离,我在另一个帮助问题中提出这个问题(如何打开多个json txt文件而不会出现错误和停止)。 Trying to get shorter way of opening multiple txt files

简而言之,我正在为每场比赛创建一个单词,将球员名称作为关键,并将他们的分数作为值。 需要进行这种比较,以过滤参加过1次以上比赛的玩家名称,并保持最高分。 但也许另一个解决方案是将所有这些不同的dicts存储在一个大的嵌套字典中。这至少是我老师给我的暗示。但我无法找到一种方法来比较嵌套的dicts,因此我们可以将所有这些分开的词汇绑定。

如果有任何信息不清楚,请告诉我,以便我可以尝试更清楚。

提前thnx

更新: 比较后得出的一个例子:

dict1 = {"name1": 100, "name2": 20, "name4": 111}
dict2 = {"name4": 112, "name5": 23}

compared_dict = {"name1": 100, "name2": 20, "name4": 112, "name5": 23}

2 个答案:

答案 0 :(得分:1)

您所描述的处理听起来并不像比较词典一样 - 似乎您想要将它们合并在一起(并且只保留每个玩家获得的最高分数)。

下面的combine_dicts()函数将接受任意数量的输入词典(由于args前缀,统称为*。)

def combine_dicts(*args):
    combined = {}
    for arg in args:
        for player, score in arg.items():
            combined[player] = max(combined.get(player, 0), score)
    return combined

dict1 = {"name1": 100, "name2": 20, "name4": 111}
dict2 = {"name4": 112, "name5": 23}

result  = combine_dicts(dict1, dict2)
print(result)

输出:

{'name1': 100, 'name2': 20, 'name4': 112, 'name5': 23}

答案 1 :(得分:1)

所以这两个规则是:

  1. 过滤掉重复的内容
  2. 如果新词典大于旧词典,则包括最新词典的分数
  3. 您正在复制大量代码......编写最佳实践的第一条规则之一是DRY(不要重复自己!)

    让我们定义合并新旧词典的方法

    def merge_dictionaries(old, new):
        changes = {}
        # keep the old one, don't edit the new one
        copy = old.copy()
        for player in new.keys():
            new_score = new[player]
            try:
                old_score = old[player]
            except KeyError:
                # if player doesn't exist in the old set, add them to the changes
                changes[player] = new_score
                continue
            if new_score > old_score:
                changes[player] = new_score
        copy.update(changes)
        return copy
    

    下一步是使用上述方法迭代这些包含播放器名称和分数的词典列表总计到最终结果。

    一种解决方案可能如下所示:

    def final_result(list_of_games):
        final = {}
        for results in list_of_games:
            final = merge_dictionaries(final, results)
        return final
    

    一个工作示例:

    def merge_dictionaries(old, new):
        changes = {}
        # keep the old one, don't edit the new one
        copy = old.copy()
        for player in new.keys():
            new_score = new[player]
            try:
                old_score = old[player]
            except KeyError:
                # if player doesn't exist in the old set, add them to the changes
                changes[player] = new_score
                continue
            if new_score > old_score:
                changes[player] = new_score
        copy.update(changes)
        return copy
    
    def final_result(list_of_games):
        final = {}
        for results in list_of_games:
            final = merge_dictionaries(final, results)
        return final
    
    games = [
        {'kevin': 1, 'jack': 5},
        {'kevin': 2, 'blueberry': 1, 'jack': 3},
        {'kevin': 1, 'blueberry': 5, 'jack': 10}
        ]
    
    print(final_result(games))
    

    哪个输出

    {'kevin': 2, 'jack': 10, 'blueberry': 5}