使用Counter对象从两个列表创建字典

4

我有以下列表:

name = ["Anne", "Jack", "Mary"]

我还有一个嵌套列表,其中每个元素都是另一个列表,并与 name 列表中的名称相连。如下所示:

n1 = [[0, 0, 3], [0, 5, 5], [1, 3, 3]]

所以对于列表name中的第一个元素'Anne',与之连接的来自n1的列表是第一个元素[0, 0, 3]。类似地,对于列表name中的第二个元素"Jack",与之连接的来自n1的列表是第二个元素[0, 5, 5],以此类推。我想要计算在n1每个元素中每个数字出现的次数,并将其以字典格式连接到name列表中的名称。所以我希望输出看起来像下面这样:
{'Anne': {'0': 2, '3': 1}, 'Jack': {'0': 1, '5': 2}, 'Mary': {'1': 1, '3': 2}}

我尝试了以下方法:
      from collections import Counter
      clust = {}
      for val in name:
         clust[val] = {}
         for e in n1:
             wc = Counter(str(e1) for e1 in e)
             clust[val] = dict(wc)

但是这给我输出了:
clust = {'Anne': {'1': 1, '3': 2}, 'Jack': {'1': 1, '3': 2}, 'Mary': {'1': 1, '3': 2}}

哪一个是不正确的?我怎样才能得到我想要的输出结果?
5个回答

4

您需要将n1的数据与name中的每个项目匹配; 最简单的方法是使用zip

>>> from collections import Counter
>>> name = ["Anne", "Jack", "Mary"]
>>> n1 = [[0,0,3], [0,5,5], [1,3,3]]
>>> {name_: Counter(data) for name_, data in zip(name, n1)}
{'Anne': Counter({0: 2, 3: 1}), 'Jack': Counter({5: 2, 0: 1}), 'Mary': Counter({3: 2, 1: 1})}

(注意使用了“字典推导”,请参见文档。)

如果你的Counter中的键是字符串很关键,你可以使用map在计数之前转换整数:

>>> {name_: Counter(map(str, data)) for name_, data in zip(name, n1)}
{'Anne': Counter({'0': 2, '3': 1}), 'Jack': Counter({'5': 2, '0': 1}), 'Mary': Counter({'3': 2, '1': 1})}

1
OP在计数器中使用了字符串键(不确定为什么,但还是+1)。 - wim
有没有办法从输出中删除关键字“Counter”? - user1452759
@user1452759 你为什么想这样做呢?你可以像对待普通的dict一样处理一个Counter,而且它还提供了额外的功能(例如most_common方法、更容易地更新更多的项、合理的算术运算)。 - jonrsharpe
我询问这个问题的原因是因为我不确定是否可以使用"Counter"关键字将"clust"字典/JSON插入MongoDB中。但是这是可能的,所以这不是问题。而且我想要将键作为"str"的原因是否则它无法插入MongoDB。 - user1452759
1
@user1452759 哦,我明白了。在大多数情况下,Counter 可以兼容 dict 的任何地方;isinstance(Counter(), dict)True,因为它是一个子类(这也是为什么首选 isinstance 而不是检查 type)。 - jonrsharpe

2
对于每个名称,您的for e in n1:循环会遍历n1中的所有元素,并为每个元素创建一个Counter,然后将clust[val]设置为结果。因此,clust[val]最终只包含n1中的最后一个项目的结果。
您应该使用zip()将两个列表名称和n1合并成一个列表,或者更好的是使用名称列表和来自n1的Counters的结果。 zip()返回从两个列表中获取的元素的元组(zip([1, 2], ['a', 'b'])变成[(1,'a'),(2,'b')] )。你可以直接从这样的元组创建一个dict
clust = dict(zip(name, [Counter(e) for e in n1]))

有没有办法从这个输出中删除关键字“Counter”? - user1452759
Counter(e)转换为dict(Counter(e)),我猜。你会失去一些方便的功能,但也许你并不需要它。 - RemcoGerlich

1

只需要使用name列表的索引值来计算n1子列表中的项目数。可以使用enumerate(name)来完成这项工作。它返回值及其索引。使用返回的索引来计算与name中的项目对应的n1子列表中的项目数。

>>> from collections import Counter
>>> name = ["Anne", "Jack", "Mary"]
>>> n1 = [[0,0,3], [0,5,5], [1,3,3]]
>>> clust = {}
>>> for i,val in enumerate(name):
...     wc = Counter(str(e1) for e1 in n1[i])
...     clust[val] = dict(wc)
... 
>>> clust
{'Anne': {'0': 2, '3': 1}, 'Jack': {'0': 1, '5': 2}, 'Mary': {'1': 1, '3': 2}}

0

你需要这样获取它

from collections import Counter
name = ["Anne", "Jack", "Mary"]
n1 = [[0,0,3], [0,5,5], [1,3,3]]
clust = {name[i]: Counter(n1[i]) for i in range(len(name))}

输出结果为:

{'Anne': Counter({0: 2, 3: 1}), 'Jack': Counter({5: 2, 0: 1}), 'Mary': Counter({3: 2, 1: 1})}


0

这里有一个一行代码可以获得你想要的输出:

zip(name, [dict(Counter(z)) for z in [[str(y) for y in x] for x in n1]])

简单来说:

  • [[str(y) for y in x] for x in n1] 将 n1 的元素转换为列表
  • dict(Counter(z)) 创建一个包含每个 n1 列表元素计数的列表
  • zip 结合这两个列表

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接