字典中最常见的值

时间:2015-11-24 18:05:40

标签: python sorting dictionary

我有以下字典:

d = {"a":["MRS","VAL"],"b":"PRS","c":"MRS","d":"NTS"}

我想创建一个字典,给出每个值的出现。基本上,它看起来像:

output = {"MRS":2,"PRS":1,"NTS":1,"VAL":1}

有谁知道我怎么能这样做? 提前致谢 !

5 个答案:

答案 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.Counteritertools.groupbyitertools.groupby的组合

  1. 只需collections.Counter

    itertools.groupby
  2. >>> 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
  3. 这就是问题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}