【问题标题】:From a list of dicts get the maximal length of the values for each key in a pythonic way从字典列表中以pythonic方式获取每个键的值的最大长度
【发布时间】:2016-02-11 14:52:12
【问题描述】:

我正在寻找一种更 Pythonic 的方式来获取字典列表中每个键的值的最大长度。

我的方法是这样的

lst =[{'a':'asdasd', 'b': 123},{'a': 'asdasdasdas'}, {'a':123,'b':'asdasd'}]
dct = {}
for l in lst:
    for key in l:
        dct.update({key: max(dct.get(key,0), len(str(l.get(key,0))))})
print(dct)

输出给出

{'b': 6, 'a': 11}

需要 str 函数来获取整数(也包括非整数)的长度

这种方法是“pythonic”还是使用列表推导或类似方法的更流畅、更易读的方法。

【问题讨论】:

  • 是 123 应该是 int 还是 string?
  • lst中每个dicts中的所有key都一样吗?
  • @SirParselot,我不知道整数。但是,我想处理 Nones -> 我使用了 str 函数。 @ Chad S. lst 中的第二个字典与其他字典没有相同的键。但是,如果您有一个使用此假设的解决方案,这也很好
  • 我认为您的示例(以及所有给出的答案)都不是 Pythonic,因为尽管他们使用 Python 习语,但它们并不“清楚”:stackoverflow.com/questions/25011078/what-does-pythonic-mean - 也许您可以更清楚地了解您的愿望是pythonic
  • 我从您的链接中引用:“所以基本上当有人说某些东西是非 Python 的时,他们是在说可以以更适合 Python 编码风格的方式重写代码。”我正在寻找这样的解决方案。因为,我是 python 新手,所以我想了解更多关于高效和清晰的编码方式。例如我的代码不是很可读。尤其是更新和最大部分可能会令人困惑。

标签: python python-3.x list-comprehension


【解决方案1】:

我喜欢这样的 Python 可读性和使用方法:

dicts = [{'a':'asdasd', 'b': 123},{'a': 'asdasdasdas'}, {'a':123,'b':'asdasd'}]

def get_highest(current_highest, items_left):
    if not items_left:
        return current_highest
    else:
        item = items_left.pop()
        higher = {key: len(str(value)) for key, value in item.items() if (len(str(item[key])) > current_highest.get(key, 0))}
    if higher:
        current_highest.update(higher)
    return get_highest(current_highest, items_left)

print(get_highest(dict(), dicts))

{'b': 6, 'a': 11}

【讨论】:

  • 我并不是说这是最“pythonic”的,它只是对我的眼睛的描述。我认为 Trey Hunners 的第二个例子是可读性最好的例子,虽然很短。
【解决方案2】:

我认为您的方法是相当 Pythonic 的,只是我会将 update 行更改为更清晰一点:

# A little terse
dct.update({key: max(dct.get(key,0), len(str(l.get(key,0))))})
# A little simpler
dct[key] = max(dct.get(key, 0), len(str(l[key])))

这是一个修改变量名的解决方案:

dict_list =[{'a':'asdasd', 'b': 123},{'a': 'asdasdasdas'}, {'a':123,'b':'asdasd'}]
max_lengths = {}
for dictionary in dict_list:
    for k, v in dictionary.items():
        max_lengths[k] = max(max_lengths.get(k, 0), len(str(v)))
print(max_lengths)

【讨论】:

    【解决方案3】:

    我之前的回答是错误的并且没有意识到,但这里有另外两个确实有效。第一个使用熊猫。它创建一个数据框,对键和值进行排序,获取每个组的第一个值,然后从中创建一个字典

    import pandas as pd
    lst = [{'a':'asdasd', 'b': 123},{'a': 'asdasdasdas'}, {'a':123,'b':'asdasd'}]
    dct={}
    
    d = pd.DataFrame([(k,len(str(v))) for i in lst for k,v in i.items()], columns=['Key','Value'])
    d = d.sort(['Key','Value'], ascending=[1,0])
    d = d.groupby('Key').first().reset_index()
    d = dict(zip(d.Key, d.Value))  #or d.set_index('Key')['Value'].to_dict()
    print d
    
    {'a': 11, 'b': 6}
    

    如果你想要一些易于阅读并使用内置模块的东西,那么应该这样做

    lst = [{'a':'asdasd', 'b': 123},{'a': 'asdasdasdas'}, {'a':123,'b':'asdasd'}]
    dct={}
    
    for i in lst:
        for k,v in i.items():
            if k in dct:
                if len(str(v)) > dct[k]:
                    dct[k] = len(str(v))
            else:
                dct[k] = len(str(v))
    print dct
    
    {'a': 11, 'b': 6}
    

    【讨论】:

    • 因此,如果我将您的答案与我的建议进行比较,本质的区别是我的 update-construct 被一个聪明的 if-else 结构所取代,对吧?
    • @Quickbeam2k1 基本上是的,它仍然循环遍历列表,但获取字典的键和值,并用易于阅读的 if-else 语句替换你的单行符
    【解决方案4】:

    其他答案侧重于使用 python 功能而不是可读性。我个人认为可读性和简单性是所有“pythonic”特征中最重要的。

    (我简化为对所有内容都使用字符串,但如果您放入 str(),它也适用于整数)

    from collections import defaultdict
    
    lst =[{'a':'asdasd', 'b': '123'},{'b': 'asdasdasdas'}, {'a':'123','b':'asdasd'}]
    
    def merge_dict(dic1,dic2) :
        for key,value in dic2.items():
                dic1[key].append(value)
    
    combined = defaultdict(list)
    for dic in lst:
        merge_dict(combined, dic)
    
    print( {key : max(map(len,value)) for key, value in combined.items() } )
    

    【讨论】:

    • 第一步只是将字典合并成一个“多值映射”——最后一行完成了所有请求的实际逻辑
    • 我的第二个答案只使用内置模块并且易于阅读。
    • @SirParselot - 我同意第二个答案相当易读。虽然第一个答案很聪明,但它在许多其他 Python 特征上都失败了。如果第二个答案是独立的,我会赞成的。
    【解决方案5】:

    这是另一种不依赖排序/压缩的方式,但我不会说其中一种比另一种更 Pythonic。

    from itertools import chain
    
    lst =[{'a':'asdasd', 'b': 123}, {'a': 'asdasdasdas'}, {'a':123,'b':'asdasd'}]
    dct = {
        k: max(len(str(d.get(k, ""))) for d in lst)
        for k in set(chain.from_iterable(d.keys() for d in lst))
    }
    
    print(dct)
    

    或者,您可以使用 groupby:

    from itertools import chain, groupby
    
    lst =[{'a':'asdasd', 'b': 123}, {'a': 'asdasdasdas'}, {'a':123,'b':'asdasd'}]
    dct = {
        k: max(len(str(v)) for _, v in g)
        for k, g in groupby(
            chain.from_iterable(d.items() for d in lst),
            lambda p: p[0]
        )
    }
    
    print(dct)
    

    【讨论】:

      猜你喜欢
      • 2012-09-06
      • 1970-01-01
      • 2021-09-13
      • 2012-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多