简体   繁体   English

使用字典理解压缩/转换嵌套列表

[英]Condenseing/converting a nested list using dictionary comprehension

So I have data structured in a nested list like so所以我的数据结构化在一个嵌套列表中

data = [['A', '1'], ['B', '2'], ['C', '3'], ['A', '-2'], ['B', '4'], ['C', '1'], ['A', '2'], ['B', '1'], ['C', '-5']]

and I am trying to convert it into an output that looks like this我正在尝试将其转换为如下所示的输出

{'A': 1, 'C': -1, 'B': 7}

Basically sum up all of the A's, B's, and C's, put output as a dictionary.基本上总结所有的 A、B 和 C,将输出作为字典。

I wrote this code which gives the correct answer我写了这段代码,给出了正确的答案

playerSum = {}
for ele in data:
    if ele[0] not in playerSum:
        playerSum[ele[0]] = int(ele[1])
    else:
        playerSum[ele[0]] += int(ele[1])

However, I am trying to convert the code block above into dictionary comprehension.但是,我正在尝试将上面的代码块转换为字典理解。 I understand mostly how to do it, but I don't understand how to write the += as a dictionary comprehension.我主要了解如何做到这一点,但我不明白如何将 += 写成字典理解。 Any guidance on the structure would be great.任何关于结构的指导都会很棒。

So far I have this到目前为止我有这个

playerSum = {ele[0]: int(ele[1]) if ele[0] not in playerSum else playerSum[ele[0]] += int(ele[1]) for ele in data}

Edit: So @achampion was able to solve it.编辑:所以@achampion 能够解决它。 Thanks!谢谢!

{key: sum(int(v) for k, v in data if k==key) for key in set(k for k, _ in data)}

It is not practical to do it as a comprehension.把它作为一种理解来做是不切实际的。
Just as an exercise you can use a coroutine to do the counting for you, but you effectively create the dictionary twice:作为练习,您可以使用协程为您进行计数,但您可以有效地创建字典两次:

from collections import defaultdict
def count():
    cache = defaultdict(int)
    k, v = yield
    while True:
        cache[k] += v
        k, v = yield cache[k]

counter = count()  # Create coroutine
next(counter)      # Prime coroutine

data = [['A', '1'], ['B', '2'], ['C', '3'], ['A', '-2'], ['B', '4'],
        ['C', '1'], ['A', '2'], ['B', '1'], ['C', '-5']]

{k: counter.send((k, int(v))) for k, v in data}  # Meets the challenge :)

Result:结果:

{'A': 1, 'B': 7, 'C': -1}

Or a truly ugly one-liner that doesn't need a coroutine and isn't quadratic (not a comprehension):或者一个真正丑陋的单行,不需要协程并且不是二次的(不是理解):

>>> reduce(lambda d, (k,v): d.__setitem__(k, d.get(k,0)+int(v)) or d, data, {})  # Py2.7
{'A': 1, 'B': 7, 'C': -1}

And finally a very inefficient but true dict comprehension based on @Prune:最后是一个基于@Prune 的非常低效但真正的 dict 理解:

>>> {key: sum(int(v) for k, v in data if k==key) for key in set(k for k, _ in data)}
{'A': 1, 'B': 7, 'C': -1}

The best way is the most obvious way最好的方法是最明显的方法

from collections import defaultdict
playerSum = defaultdict(int)

for key, value in data:
   playerSum[key] += int(value)

It is not possible to use a dict comprehension as your values would be overwritten, the dict does not get created until the comprehension is finished so even if you could there is nothing to +=.这是不可能使用字典理解为你的价值观会被覆盖,该字典还没有生成,直到理解完成即便如此,如果你能有什么好+ =。 As it stands unless you have playerSum = {} somewhere your code will error with a NameError, if you do you are simply rebinding the name to the result of your dict comp so playerSum = {} is basically doing nothing.就目前而言,除非您在某处有playerSum = {}否则您的代码将出现 NameError 错误,如果您这样做,您只是将名称重新绑定到 dict comp 的结果,因此playerSum = {}基本上什么都不做。

The only way to do what you want is to along the lines of your own solution .做你想做的唯一方法是按照你自己的解决方案。 For more efficient approach You can unpack the sublists and cast the second element to int, summing the value using a collections.defaultdict :为了更有效的方法您可以解压缩子列表并将第二个元素转换为 int,使用collections.defaultdict对值求和:

from collections import defaultdict

d = defaultdict(int)

for a,b  in data:
    d[a] += int(b)

print(d)
defaultdict(<type 'int'>, {'A': 1, 'C': -1, 'B': 7})

Or using a regular dict:或使用常规字典:

d = {}

for a, b in data:
    d[a] = d.get(a,0) + int(b)

print(d)
{'A': 1, 'C': -1, 'B': 7}

I did it in a single comprehension, as you asked.正如你所问的,我是在一个单一的理解中做到的。

dict ([(key, sum(int(elem[1]) for elem in data if elem[0]==key)) for key in [id for id in set([elem[0] for elem in data])] ])

From outer to inner:从外到内:

  • Build a set of the ID's used in the list.构建列表中使用的一组 ID。

  • For each ID, make a list of the associated values.对于每个 ID,列出相关值。

  • Sum the list.汇总列表。

  • Emit (yield) the ID and sum as a pair.发出(产生)ID 并成对求和。

  • Turn this list of tuples into a dictionary.将这个元组列表变成字典。

Test:测试:

data = [['A', '1'], ['B', '2'], ['C', '3'],
        ['A', '-2'], ['B', '4'], ['C', '1'],
        ['A', '2'], ['B', '1'], ['C', '-5']]
playerSum = dict ([(key, sum(int(elem[1]) for elem in data if elem[0]==key))
                   for key in [id for id in set([elem[0] for elem in data])] ])
print data
print playerSum

Result:结果:

[['A', '1'], ['B', '2'], ['C', '3'], ['A', '-2'], ['B', '4'], ['C', '1'], ['A', '2'], ['B', '1'], ['C', '-5']]
{'A': 1, 'C': -1, 'B': 7}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM