【问题标题】:Get max from dict.values() with the same key使用相同的键从 dict.values() 获取最大值
【发布时间】:2018-08-09 22:42:07
【问题描述】:

我有这个 csv.file。假设我已经使用了DictReader,现在我有一些完整的字典列表,比如('name': 'Andrew'), ('points': 18) 等。

name    points
Andrew  18
Kate    10
Jack    55
Andrew  31
Andrew  100
Jack    58
Andrew  34
Kate    22
Jack    5
Andrew  72

我要做的是返回一个像Andrew: (5, 100)这样的键值对,其中的值是:

  1. 我在列表中遇到过这个名字多少次;
  2. points 表中此名称的最大数量。

我对第一个任务没有问题,但找不到解决方案 第二个。这就是我试图做的:

name_counter = defaultdict(int)
max_points = defaultdict(int)
for dictionary in list_from_csv:
    name_counter[dictionary['name']] += 1 #every time I meet the name, I add +1 to the value
    max_points[dictionary['name']] = ??? 

我想只使用max(dictionary[points]),但 max 应该从数字的数量中选择,而不仅仅是一个。也许创建一个列表,但不确定如何。还有其他想法吗?

不胜感激。

附:在我拥有这两个字典之后,我需要根据密钥合并它们,但我希望这不是那么难。

【问题讨论】:

  • 合并后的字典应该是什么样子的?
  • 谷歌如何使用groupby函数。我想你可以从那里完成。
  • 你展示的不是一个充满字典的列表,它甚至不是 anything 的合法 Python 语法。如果您希望我们向您展示如何转换该输入,请给我们一个可用的示例输入。

标签: python dictionary iteration


【解决方案1】:

您只需要弄清楚每次获得新值时如何处理max_points[name],对吗?

让我们假设,在每次迭代中,max_points[name] 已正确设置为您目前看到的最高值。那么,您需要如何处理新值?

简单:如果points 大于你目前看到的最高值,它就是新的最高值;如果不是,旧的最高值就是新的最高值。

这正是max 所做的。所以:

max_points[dictionary['name']] = max(max_points[dictionary['name']], points)

现在我们只需要验证假设是否正确。

  • 由于您使用的是defaultdict(int),它始终从 0 开始。如果您可以得到负分,那已经是错误的,否则,它是正确的 - 迄今为止您看到的最高分,对于任何人, 为 0。

  • 在每一步中,如果上一步正确,那么在下一步之后也是正确的,因为这就是max 所做的。

  • 所以,通过归纳,最后是正确的。


作为旁注,不要一遍又一遍地重复dictionary['name'],它可能看起来像这样更好:

for dictionary in list_from_csv:
    name = dictionary['name']
    name_counter[name] += 1
    max_points[name] = max(max_points[name], points)

【讨论】:

  • 我的天,谢谢!:) 这真是一个很好的答案!
【解决方案2】:

你可以使用itertools.groupby:

import itertools
data = [{'name': 'Andrew', 'points': 18}, {'name': 'Kate', 'points': 10}, {'name': 'Jack', 'points': 55}, {'name': 'Andrew', 'points': 31}, {'name': 'Andrew', 'points': 100}, {'name': 'Jack', 'points': 58}, {'name': 'Andrew', 'points': 34}, {'name': 'Kate', 'points': 22}, {'name': 'Jack', 'points': 5}, {'name': 'Andrew', 'points': 72}]
grouped_data = [[a, list(b)] for a, b in itertools.groupby(sorted(data, key=lambda x:x['name']), key=lambda x:x['name'])]
final_data = [{a:(len(b), max(b, key=lambda x:x['points'])['points'])} for a, b in grouped_data]

输出:

[{'Andrew': (5, 100)}, {'Jack': (3, 58)}, {'Kate': (2, 22)}]

【讨论】:

  • 谢谢,这真的很有帮助!
【解决方案3】:

为了完整起见,这里是第 3 方 Pandas 单线:

res = df.groupby('name')['points'].agg(['size', 'max'])

结果

print(res)

        size  max
name             
Andrew     5  100
Jack       3   58
Kate       2   22

设置

import pandas as pd
from io import StringIO

mystr = StringIO("""name    points
Andrew  18
Kate    10
Jack    55
Andrew  31
Andrew  100
Jack    58
Andrew  34
Kate    22
Jack    5
Andrew  72""")

df = pd.read_csv(mystr, delim_whitespace=True)

【讨论】:

    【解决方案4】:

    这是一个不使用除 csv 之外的任何额外导入的解决方案。

    我已将您的示例数据用作 csv 文件。我已阅读内容并创建了 (name, points) 的元组列表

    import csv
    list_of_tuples = []
    
    with open('f1.csv', newline='') as csv_file:
        dict_of_csv = csv.DictReader(csv_file)
        for item in dict_of_csv:
            list_of_tuples.append((item['name'], item['points']))
    

    list_of_tuples 看起来像这样

    [('Andrew', '18'), ('Kate', '10'), ('Jack', '55'), ('Andrew', '31'), ('Andrew', '100'), ('Jack', '58'), ('Andrew', '34'), ('Kate', '22'), ('Jack', '5'), ('Andrew', '72')]
    

    result_dict 以 {key: (tuple_0, tuple_1), } 格式存储数据 喜欢

    { name: (name_count, max_points),
      name1: (name_count1, max_points1),
      ...
    }
    

    字典中的值由它们的key 标识,在本例中为name
    喜欢dictionary['key'] 所以这里是result_dict[name] 元组中的数据可以作为普通列表访问,例如 tuple[0] 和 tuple[1]
    所以这里是result_dict[name][0]result_dict[name][1]

    result_dict = {}
    for dict_item in list_of_tuples:
        name = dict_item[0]
        points = int(dict_item[1])
        if name in result_dict:
            name_count = result_dict[name][0]
            max_points = result_dict[name][1]
            result_dict[name] = (name_count + 1, points if max_points < points else max_points)
        else:
            # the name isn't in the dictionary, so we add the "name: (name_count, max_points)" to it
            result_dict[name] = (1, points)
    

    输出是:

    {'Andrew': (5, 100), 'Kate': (2, 22), 'Jack': (3, 58)}
    

    【讨论】:

    • 谢谢你这么详细的回答!
    猜你喜欢
    • 2022-11-17
    • 1970-01-01
    • 1970-01-01
    • 2023-01-20
    • 1970-01-01
    • 1970-01-01
    • 2016-06-26
    • 2018-09-10
    • 1970-01-01
    相关资源
    最近更新 更多