【问题标题】:Python - 2D list - find duplicates in one column and sum values in another columnPython - 2D 列表 - 在一列中查找重复项并在另一列中求和值
【发布时间】:2022-01-04 03:49:57
【问题描述】:

我有一个 2D 列表,其中分别包含足球运动员的姓名、他们进球的次数以及他们尝试射门的次数。

player_stats = [['Adam', 5, 10], ['Kyle', 12, 18], ['Jo', 20, 35], ['Adam', 15, 20], ['Charlie', 31, 58], ['Jo', 6, 14], ['Adam', 10, 15]]

从这个列表中,我试图返回另一个列表,该列表仅显示每个玩家的一个实例以及他们各自的 total 目标和 total 目标尝试,就像这样:

player_stats_totals = [['Adam', 30, 45], ['Kyle', 12, 18], ['Jo', 26, 49], ['Charlie', 31, 58]]

在 Stack Overflow 上搜索后,我了解到(来自 this thread)如何返回重复播放器的索引

x = [player_stats[i][0] for i in range (len(player_stats))]

for i in range (len(x)):
    if (x[i] in x[:i]) or (x[i] in x[i+1:]): print (x[i], i)

但被困在如何进行之后,如果这种方法确实与我需要的东西严格相关(?)

返回所需总计列表的最有效方法是什么?

【问题讨论】:

    标签: python list duplicates


    【解决方案1】:

    使用字典来累积给定玩家的值:

    player_stats = [['Adam', 5, 10], ['Kyle', 12, 18], ['Jo', 20, 35], ['Adam', 15, 20], ['Charlie', 31, 58], ['Jo', 6, 14], ['Adam', 10, 15]]
    
    lookup = {}
    for player, first, second in player_stats:
        
        # if the player has not been seen add a new list with 0, 0 
        if player not in lookup:
            lookup[player] = [0, 0]
        
        # get the accumulated total so far 
        first_total, second_total = lookup[player]
        
        # add the current values to the accumulated total, and update the values 
        lookup[player] = [first_total + first, second_total + second]
    
    # create the output in the expected format
    res = [[player, first, second] for player, (first, second) in lookup.items()]
    print(res)
    

    输出

    [['Adam', 30, 45], ['Kyle', 12, 18], ['Jo', 26, 49], ['Charlie', 31, 58]]
    

    一个更高级的 pythonic 版本是使用collections.defaultdict:

    from collections import defaultdict
    
    player_stats = [['Adam', 5, 10], ['Kyle', 12, 18], ['Jo', 20, 35],
                    ['Adam', 15, 20], ['Charlie', 31, 58], ['Jo', 6, 14], ['Adam', 10, 15]]
    
    lookup = defaultdict(lambda: [0, 0])
    for player, first, second in player_stats:
        # get the accumulated total so far
        first_total, second_total = lookup[player]
    
        # add the current values to the accumulated total, and update the values
        lookup[player] = [first_total + first, second_total + second]
    
    # create the output in the expected format
    res = [[player, first, second] for player, (first, second) in lookup.items()]
    
    print(res)
    

    这种方法的优点是跳过初始化。两者的方法都是 O(n)。

    备注

    表达式:

    res = [[player, first, second] for player, (first, second) in lookup.items()]
    

    是一个list comprehension,相当于下面的for循环:

    res = []
    for player, (first, second) in lookup.items():
        res.append([player, first, second])
    

    另外,阅读this 了解解包。

    【讨论】:

    • 哇,我非常感谢 cmets 解释代码的详细回复。输出正是我想要的,因此打勾。再次感谢!
    【解决方案2】:

    您要做的是使用字典,其中键是球员姓名,值是包含 [进球、射门] 的列表。构建它看起来像这样:

    all_games_stats = {}
    for stat in player_stats:
        player, goals, shots = stat
        if player not in all_games_stats:
            all_games_stats[player] = [goals, shots]
        else:
            stat_list = all_games_stats[player]
            stat_list[0] += goals
            stat_list[1] += shots
    

    然后,如果您想将球员及其统计数据表示为一个列表,您可以: 列表(all_games_stats.items())

    【讨论】:

    • 非常感谢您的回复和帮助。当我运行代码时,它返回了一个列表中的元组:[('Adam', [30, 45]), ('Kyle', [12, 18]), ('Jo', [26, 49 ]), ('查理', [31, 58])]。我希望返回是列表,以便以后可以根据需要操作它们,并且根据我对 Python 的新手知识,我不确定是否可以使用元组来做到这一点。
    【解决方案3】:

    您可以将列表转换为字典。 (一旦完成,它总是可以改回来)这有效:

    player_stats = [['Adam', 5, 10], ['Kyle', 12, 18], ['Jo', 
    20, 35], ['Adam', 15, 20], ['Charlie', 31, 58], ['Jo', 6, 
    14], ['Adam', 10, 15]]
    
    new_stats = {}
    
    
    for item in player_stats:
        if not item[0] in new_stats:
            new_stats[item[0]] = [item[1],item[2]]
        else:
            new_stats[item[0]][0] += item[1]
            new_stats[item[0]][1] += item[2]
    
    print(new_stats)
    

    【讨论】:

    • 非常感谢您的快速回复并提供解决方案。当我运行你的代码时,它返回了一个字典{'Adam': [30, 45], 'Kyle': [12, 18], 'Jo': [26, 49], 'Charlie': [31, 58]},并且通过一些研究,我相信我会学习如何将它转换回一个列表。我将勾选授予@Dani,因为输出是我想要的列表。再次感谢您!
    【解决方案4】:

    我也不妨提交一些东西。这是另一种具有一些列表理解的方法:

    # Unique values to new dictionary with goal and shots on goal default entries 
    agg_stats = dict.fromkeys(set([p[0] for p in player_stats]), [0, 0])
    
    # Iterate over the player stats list
    for player in player_stats:
        # Set entry to sum of current and next stats values for the corresponding player.
        agg_stats[player[0]] = [sum([agg_stats.get(player[0])[i], stat]) for i, stat in enumerate(player[1:])]
    

    【讨论】:

    • 非常感谢您提交您的方法。当我运行你的代码时,我没有得到输出。我敢肯定,我将能够弄清楚如何按预期输出列表 - 我相信这很简单,尽管对于 Python 来说是新手,它可能需要另一篇文章。 @Dani 的回答提供了我正在寻找的解决方案。
    • 我现在看到添加print(agg_stats) 会返回一个包含总值{'Adam': [30, 45], 'Jo': [26, 49], 'Kyle': [12, 18], 'Charlie': [31, 58]} 的字典
    • sum([x, y])代替x + y有什么意义?
    • @KellyBundy 没有意义,真的。要么工作。感谢您的提问!
    【解决方案5】:

    另一种方式,将整个 三元组(包括名称)存储在 dict 中并更新它们:

    stats = {}
    for name, goals, attempts in player_stats:
        entry = stats.setdefault(name, [name, 0, 0])
        entry[1] += goals
        entry[2] += attempts
    player_stats_totals = list(stats.values())
    

    为了好玩,还有一个复数的解决方案,这使得添加很好,但需要烦人的转换:

    from collections import defaultdict
    
    tmp = defaultdict(complex)
    for name, *stats in player_stats:
        tmp[name] += complex(*stats)
    player_stats_totals = [[name, int(stats.real), int(stats.imag)]
                           for name, stats in tmp.items()]
    

    【讨论】:

    • 是的,确实,通过添加print(player_stats_totals) 会产生所需的结果,非常感谢您提供解决方案。
    猜你喜欢
    • 2021-04-19
    • 2015-03-23
    • 2020-01-08
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    • 1970-01-01
    • 2017-04-28
    相关资源
    最近更新 更多