我有以下字典:
d = {"a":["MRS","VAL"],"b":"PRS","c":"MRS","d":"NTS"}
我想创建一个字典,给出每个值的出现。基本上,它看起来像:
output = {"MRS":2,"PRS":1,"NTS":1,"VAL":1}
有谁知道我怎么能这样做? 提前致谢 !
答案 0 :(得分:7)
由于你的dict由字符串和字符串列表组成,你首先需要flatten这些元素到一个普通类型的字符串:
import collections
d = {"a":["MRS","VAL"],"b":"PRS","c":"MRS","d":"NTS"}
def flatten(l):
for el in l:
if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
for sub in flatten(el):
yield sub
else:
yield el
>>> list(flatten(d.values()))
['MRS', 'VAL', 'MRS', 'PRS', 'NTS']
然后,您可以使用Counter来计算每个字符串的出现次数:
>>> collections.Counter(flatten(d.values()))
Counter({'MRS': 2, 'NTS': 1, 'PRS': 1, 'VAL': 1})
答案 1 :(得分:4)
如上所述,您可以使用Rails.application.configure do
config.cache_classes = true
config.eager_load = false
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
config.assets.digest = true
config.log_level = :info
config.force_ssl = true
config.action_mailer.smtp_settings = {:enable_starttls_auto => false}
config.action_mailer.delivery_method = :sendmail
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
Rails.application.config.middleware.use ExceptionNotification::Rack,
:email => {
:email_prefix => "[PRODUCTION] ",
:sender_address => %{"notifier" <errors@something.com>},
:exception_recipients => %w{team@something.com}
}
end
,因为这是一种显而易见的方法,否则您可以使用collections.Counter
或itertools.groupby
和itertools.groupby
的组合
只需collections.Counter
itertools.groupby
>>> from itertools import groupby
>>> a, b = [list(g) for _, g in groupby(d.values(), type)]
>>> {k: len(list(g)) for k, g in groupby(sorted(a[0] + b))}
{'NTS': 1, 'VAL': 1, 'PRS': 1, 'MRS': 2}
和itertools.groupby
collections.Counter
这就是问题OP的工作虽然不健全。
答案 2 :(得分:1)
通常,您可以使用Counter
将键映射到计数 - 它基本上是multiset。
由于你的dict是多维的,你必须进行一些转换,但如果你只是迭代你的dict中的每个值和子值并将其添加到Counter
实例,你将会得到你想要的东西。
这是第一次通过实施;根据{{1}}将包含的具体内容,您可能需要稍微调整一下:
d
请注意,我们会检查counts = Counter()
for elem in d.values():
if isinstance(obj, Iterable) and not isinstance(elem, types.StringTypes):
for sub_elem in elem:
counter.add(sub_elem)
else:
counter.add(elem)
is an iterable and not a string。 Python无法轻松区分字符串和集合,因此如果您知道elem
仅包含字符串和列表(例如),则可以执行d
等操作。如果您无法保证isinstance(elem, list)
的值都是列表(或元组等),则最好明确排除字符串。
此外,如果d
可以包含递归密钥(例如包含包含字符串的列表的列表),这将是不够的;你可能想写一个递归函数来展平所有内容,比如dawg的解决方案。
答案 3 :(得分:1)
我很懒,所以我将使用库函数为我完成工作:
import itertools
import collections
d = {"a": ["MRS", "VAL"], "b": "PRS", "c": "MRS", "d": "NTS"}
values = [[x] if isinstance(x, basestring) else x for x in d.values()]
counter = collections.Counter(itertools.chain.from_iterable(values))
print counter
print counter['MRS'] # Sampling
输出:
Counter({'MRS': 2, 'NTS': 1, 'PRS': 1, 'VAL': 1})
2
最后,计数器就像你想要的字典一样。
考虑这一行:
values = [[x] if isinstance(x, basestring) else x for x in d.values()]
在这里,我将字典d
中的每个值都转换为一个列表,以便于处理。 values
可能类似于以下内容(顺序可能不同,这很好):
# values = [['MRS', 'VAL'], ['MRS'], ['PRS'], ['NTS']]
接下来是表达式:
itertools.chain.from_iterable(values)
返回一个使列表变平的生成器,从概念上讲,列表现在看起来像这样:
['MRS', 'VAL', 'MRS', 'PRS', 'NTS']
最后,Counter类获取该列表并计数,因此我们得到了最终结果。
答案 4 :(得分:0)
你可以通过内置功能这样做:
>>> d = {"a":["MRS","VAL"],"b":"PRS","c":"MRS","d":"NTS"}
>>>
>>> flat = []
>>> for elem in d.values():
if isinstance(elem, list):
for sub_elem in elem:
flat.append(sub_elem)
else:
flat.append(elem)
>>> flat
['MRS', 'VAL', 'MRS', 'PRS', 'NTS']
>>>
>>> output = {}
>>>
>>> for item in flat:
output[item] = flat.count(item)
>>>
>>> output
{'NTS': 1, 'PRS': 1, 'VAL': 1, 'MRS': 2}