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

Posted

技术标签:

【中文标题】使用 Counter 对象从两个列表中创建字典【英文标题】:Make dictionary from two lists using Counter object 【发布时间】:2015-02-03 11:52:14 【问题描述】:

我有以下清单:

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

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

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

所以对于'Anne',列表name 中的第一个元素,与它相连的n1 的列表是第一个元素[0, 0, 3]

同样,对于"Jack",列表name中的第二个元素,与之相连的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

这是不正确的。如何实现我想要的输出?

【问题讨论】:

【参考方案1】:

您需要将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)

(注意“字典理解”的使用,参见the docs。)

如果您的Counters 中的键是字符串至关重要,您可以使用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)

【讨论】:

OP 在计数器中有字符串键(不知道为什么,反正 +1) 是否可以从输出中删除关键字“Counter”? @user1452759 你为什么要这样做?您可以将Counter 视为普通的dict,它为您提供了额外的功能(例如most_common 方法、使用更多项目轻松更新、合理的算术)。 我之所以要求这样做是因为我不确定是否可以使用“Counter”关键字将“clust”dict/json 插入到 MongoDB。但这是可能的。所以这不是问题。还有我希望键为“str”的原因是因为它不会插入到 MongoDB 中 @user1452759 啊,我明白了。在大多数情况下,Counterdict 的任何位置都兼容; isinstance(Counter(), dict)True,因为它是一个子类(这就是为什么 isinstance 也比检查 type 更受欢迎)。【参考方案2】:

对于每个名称,for e in n1: 循环遍历 n1 的所有元素,为每个元素创建一个 Counter,并将 clust[val] 设置为结果。所以clust[val] 最终只作为n1 中最后一项的结果。

您应该使用zip() 将两个列表 name 和 n1 合并为一个,或者可能更好,名称列表和来自 n1 的结果计数器。 zip() 返回包含两个列表中元素的元组 (zip([1, 2], ['a', 'b']) becomes [(1, 'a'), (2, 'b')]。您可以直接从这些元组中创建一个 dict

所以:

clust = dict(zip(name, [Counter(e) for e in n1]))

【讨论】:

有没有办法从这个输出中删除关键字“Counter”? Counter(e) 变成dict(Counter(e)),我猜。你失去了一些方便的功能,但你可能不需要它。【参考方案3】:

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

>>> 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

【讨论】:

【参考方案4】:

这是获得您想要的输出的单行:

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 结合了两个列表

【讨论】:

【参考方案5】:

你需要像这样得到这个

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)

【讨论】:

以上是关于使用 Counter 对象从两个列表中创建字典的主要内容,如果未能解决你的问题,请参考以下文章

python库整理: Collections.Counter

如何从具有不同长度列表的字典中创建字典列表

如何从字典列表中创建数据框 [关闭]

一个班轮:从列表中创建一个字典,索引为键

我需要从包含列表的字典中使用 MultiIndex 在 Pandas 中创建一个 DataFrame

从字典列表中创建一个带有漂亮表的表