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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了寻找更优雅(更少代码)的方式来比较多个dicts相关的知识,希望对你有一定的参考价值。

不久前我问了一个关于比较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}

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

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

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

提前致谢

更新:比较后到达的示例:

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

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

所以这两个规则是:

  1. 过滤掉重复的内容
  2. 如果新词典大于旧词典,则包括该词典的得分

你正在复制很多代码......编写最佳实践的第一条规则之一是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}
另一答案

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

下面的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}

以上是关于寻找更优雅(更少代码)的方式来比较多个dicts的主要内容,如果未能解决你的问题,请参考以下文章

更简洁优雅的 VARIANT 类型使用方式

寻找 Java 代码美化器(或者可能不是美化,而是让代码更优雅的东西)[关闭]

更简洁/优雅的方式来连接 fetch() 返回的 JSON 元素

C++那些事之优雅的解析XML

同时声明多个变量的更优雅的方式

MATLAB:寻找更快/更优雅的方法来计算非常长的时间序列的移动中值绝对偏差