【问题标题】:Dictionary comprehension to get average per keyed item from a list of tuples with repeated key values字典理解从具有重复键值的元组列表中获取每个键项的平均值
【发布时间】:2020-09-03 00:58:11
【问题描述】:
mylist = [(0.8132195134810816, 'A'), (0.79314903781799, 'B'), (0.3931539216409497, 'A'), (0.23487952756579994, 'B'), (0.06686513021322447, 'C'), (0.008103227303653366, 'C'), (0.007403104126575008, 'D'), (-0.0041128367759631496, 'D'), (-0.005739579154553378, 'D'), (-0.008074572907817046, 'B')]

#我已经尝试了一些转换。请注意,我可以使用 for 循环来做到这一点。我想知道#there 是否有办法通过字典理解来做到这一点。当然,我可以构建一个常规的#dictionary,但希望有一系列过滤器单行。

newdict = dict()
for symbol in ['A','B','C','D']:  # semesters        
    values = [item for item, symbol_item in mylist if symbol_item == symbol]
    print (symbol, sum(values)/len(values))
    newdict[symbol] = sum(values)/len(values)

#我希望有办法不列出符号

#尝试使用默认字典将键的值放入列表中,但这不起作用。

mydict = defaultdict(list)
mydict.update({key: (mydict[key] + [value]) for value,key in my list})

【问题讨论】:

    标签: python dictionary dictionary-comprehension


    【解决方案1】:

    您可以使用itertools.groupbystatistics.mean 确保输入按字母排序,这里我使用operator.itemgetter 即时获取数字和字母:

    from itertools import groupby
    from statistics import mean
    from operator import itemgetter
    
    mylist = [(0.8132195134810816, 'A'), (0.79314903781799, 'B'), (0.3931539216409497, 'A'), (0.23487952756579994, 'B'), (0.06686513021322447, 'C'), (0.008103227303653366, 'C'), (0.007403104126575008, 'D'), (-0.0041128367759631496, 'D'), (-0.005739579154553378, 'D'), (-0.008074572907817046, 'B')]
    
    get_key = itemgetter(1)
    get_value = itemgetter(0)
    sorted_list = sorted(mylist, key=get_key)
    
    newdict = {k: mean(map(get_value, g)) for k, g in groupby(sorted_list, get_key)}
    
    print(newdict)
    

    {'A': 0.6031867175610156, 'B': 0.33998466415865763, 'C': 0.03748417875843892, 'D': -0.0008164372679805064}
    

    【讨论】:

    • 谢谢。感谢您的帮助。
    【解决方案2】:

    可以做到这一点,但它总是会很丑。在 Python 3.8+ 中,您可以使用赋值表达式来赋值:

    >>> mylist = [(0.8132195134810816, 'A'), (0.79314903781799, 'B'), (0.3931539216409497, 'A'), (0.23487952756579994, 'B'), (0.06686513021322447, 'C'), (0.008103227303653366, 'C'), (0.007403104126575008, 'D'), (-0.0041128367759631496, 'D'), (-0.005739579154553378, 'D'), (-0.008074572907817046, 'B')]
    >>> result = {
    ...     symbol : sum((values:= [item for item, symbol_item in mylist if symbol_item == symbol])) / len(values)
    ...     for symbol in ['A','B','C','D']
    ... }
    >>> result
    {'A': 0.6031867175610156, 'B': 0.33998466415865763, 'C': 0.03748417875843892, 'D': -0.0008164372679805064}
    

    但是这实在是让人迷惑不解。你不应该努力将你的代码塞进一行代码,那很糟糕。相反,您应该尝试编写可读、高效且可维护的代码

    理解结构有时会让你的代码更具可读性,这是它们的主要优势,如果不是像这里那样,那么你不应该使用它。

    注意,如果没有赋值表达式,您将不得不依赖另一个 for 子句来赋值给 values

    >>> result = {
    ...     symbol : sum(values) / len(values)
    ...     for symbol in ['A','B','C','D']
    ...     for values in ([item for item, symbol_item in mylist if symbol_item == symbol],)
    ... }
    >>> result
    {'A': 0.6031867175610156, 'B': 0.33998466415865763, 'C': 0.03748417875843892, 'D': -0.0008164372679805064}
    

    但实际上,与常规的 for 循环相比,这并没有增加清晰度。

    你可以迭代:

    [item for item, symbol_item in mylist if symbol_item == symbol]
    

    两次,一次是求总和,一次是为了获得长度,但我什至不会写出那种疯狂。

    现在,执行此 IMO 的最佳方法是使用分组习语,您的代码保持线性时间,您甚至不需要提前知道符号:

    >>> from collections import defaultdict
    >>> result = defaultdict(list)
    >>> for value, symbol in mylist:
    ...     result[symbol].append(value)
    ...
    >>> result = {symbol: sum(values)/len(values) for symbol, values in result.items()}
    >>> result
    {'A': 0.6031867175610156, 'B': 0.33998466415865763, 'C': 0.03748417875843892, 'D': -0.0008164372679805064}
    

    【讨论】:

    • 谢谢。我衷心感谢。对于你关于“你应该尝试编写可读、高效和可维护的代码”的观点,我也同意,并且单行的目标是我对可读、高效和可维护的代码的摘要描述。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多