从具有多个重复键的字典列表中创建字典,然后从该列表中选择最大值

时间:2018-11-29 18:45:15

标签: python python-2.7 dictionary

我知道有很多与字典操作有关的帖子,但是我找不到特殊情况的解决方案。 我有字典的列表(重复的字典键具有相似或不同的值),我必须从该列表中创建一个新字典。 例如:

a = [{u'a': 1}, {u'a': 2}, {u'a': 1}, {u'b': 2}, {u'b': 1}, {u'c': 1}, {u'c': 1}]

我正在寻找的输出:

{'a': 2, 'b':2, 'c': 1}

因此,如您所见,我只希望列表中每个键有一个条目,并且该键的值将是所有值的最大值。希望它不要太混乱。 我有一个工作中的灵魂,但是我只是想检查一下是否有更多的pythonic答案(用更少的#of线或更好的方法) 这是我的工作解决方案:

d = {}
for i in a:
    if not d.get(i.keys()[0]):
        d.update(i)
    elif d.get(i.keys()[0], 0) < i.values()[0]:
        d.update(i)
print d

感谢您的光临。

4 个答案:

答案 0 :(得分:2)

您可以对列表a进行排序,以使类似的键成为组,并且最大的值位于最后。然后添加值,以使最后一个值是字典中剩余的值:

>>> a = [{u'a': 1}, {u'a': 2}, {u'a': 1}, {u'b': 2}, {u'b': 1}, {u'c': 1}, {u'c': 1}]
>>> {k:v for k,v in (x.items()[0] for x in sorted(a))}
{u'a': 2, u'c': 1, u'b': 2}

或者,替代语法:

>>> dict(x.items()[0] for x in sorted(a))

对于Python 2和3语法:

>>> {k:v for k,v in (sorted(list(x.items())[0] for x in a))}
{'a': 2, 'b': 2, 'c': 1}
>>> dict(sorted(list(x.items())[0] for x in a))
{'a': 2, 'b': 2, 'c': 1}

来自评论:这是怎么回事?

首先,让我们提出一个更具启发性的示例:

>>> a = [{u'a': -1}, {u'a': -11}, {u'a': -3}, {u'b': 0}, {u'b': 100}, {u'c': 3}, {u'c': 1}]

因此,这里的期望结果是键(对于在dict中或使用OrderedDict保持顺序的Python 3)将是i)一组排序值中的键,然后ii)将值解释为递增值中的数字。

所以请先尝试:

>>> sorted(list(x.items())[0] for x in a)
[('a', -11), ('a', -3), ('a', -1), ('b', 0), ('b', 100), ('c', 1), ('c', 3)]

将其分解:

sorted(list(x.items())[0] for x in a)
       ^                            ^ comprehension of
                                 ^  a list of one element dicts
         ^       ^     ^            convert to a two element tuple
  ^                                 sort the tuple first by key, then by value

因此可以通过首先按键对元组进行排序,然后按值对元组进行排序。

这会导致使用groupby的替代解决方案:

>>> from itertools import groupby
>>> for k,v in groupby(sorted(list(x.items())[0] for x in a), key=lambda t: t[0]):
...     print(k, max(v))
... 
a ('a', -1)
b ('b', 100)
c ('c', 3)

groupby解决方案在内存上更加友好,因为它不会创建额外的列表。第一种解决方案可能会以较小的字典列表而更快,因为排序更容易(但您需要对其进行测试。)

在我给出的解决方案中,并不是必需,而是将密钥进行了分组(groupby才能正常工作)。这也可以:

 >>> sorted((list(x.items())[0] for x in a), key=lambda t: t[1])
 [('a', -11), ('a', -3), ('a', -1), ('b', 0), ('c', 1), ('c', 3), ('b', 100)]

然后使用dict构造函数将其转换为dict。回想一下,该列表包含(key, value)的元组列表:

>>> dict(sorted((list(x.items())[0] for x in a), key=lambda t: t[1]))
{'a': -1, 'b': 100, 'c': 3}

答案 1 :(得分:1)

您可以这样做:

a = [{u'a': 1}, {u'a': 2}, {u'a': 1}, {u'b': 2}, {u'b': 1}, {u'c': 1}, {u'c': 1}]

result = {}
for di in a:
    for key, value in di.items():
        result[key] = max(value, result.get(key, value))
print(result)

输出

{'a': 2, 'c': 1, 'b': 2}

答案 2 :(得分:1)

您可以使用defaultdict

from collections import defaultdict

d = defaultdict(lambda: 0)
for val in a:
    if d[val.keys()[0]] < val.values()[0]:
        d[val.keys()[0]] = val.values()[0]

输出

{u'a': 2, u'b': 2, u'c': 1}

答案 3 :(得分:1)

如果给定密钥不在新字典中或其值低于原始值,则可以通过遍历所有字典并用其内容更新最终字典new_a来实现。

a = [{u'a': 1}, {u'a': 2}, {u'a': 1}, {u'b': 2}, {u'b': 1}, {u'c': 1}, {u'c': 1}]
new_a = {}

for dict_ in a:
    key, value = list(dict_.items())[0]
    if key not in new_a or new_a[key] < value:
        new_a[key] = value

print(new_a) # -> {'c': 1, 'b': 2, 'a': 2}