使用 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。)
如果您的Counter
s 中的键是字符串至关重要,您可以使用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 啊,我明白了。在大多数情况下,Counter
与dict
的任何位置都兼容; 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