【问题标题】:Reverse multiple values with keys in dictionary使用字典中的键反转多个值
【发布时间】:2013-12-04 22:31:12
【问题描述】:

我对 Python 和整体编程很陌生,所以请耐心等待。

我有一个 ['Male', 'Female', 'Eunuch'] 的字典作为值和不同的名称作为键:

Persons = { 'Hodor' : 'Male', 'Tyrion': 'Male', 'Theon': 'Male', 'Arya': 'Female', 'Daenerys': 'Female', 'Sansa': 'Female', 'Varys': 'Eunuch}

我想订购它们到{ Gender: {Names: Counts}}

这样:

输入: lst = ['Hodor', 'Hodor', 'Tyrion', 'Tyrion', 'Tyrion', 'Arya', 'Daenerys', 'Daenerys', 'Varys']

输出: {'Male': {'Hodor': 2, 'Tyrion': 3, Theon: 0}, 'Female': {'Arya': 1, 'Daenerys': 2, 'Sansa': 0}, 'Eunuch': {'Varys': 1}}

我尝试的第一件事是编写计数代码:

counts = {}
for key in Persons: 
    counts[key] = 0 

for key in lst:
    counts[key] += 1

我的字典 D 现在包含计数,但我如何将它们一起计算?

Names = Persons.keys() Gender = Persons.values() Counts = counts.values() Names = counts.keys()

如果未提及变量,则输出中不应出现性别“太监”。 我尝试过不同的东西,但是当我尝试连接它们时。我尝试用值切换键,但只出现一个名称。

希望它对我想做的事情有意义:)

编辑:如果没有提到 Sansa 并且其他女性是她的值应该是 0。我希望能够操纵这些数字。说明与所有男性相比,提到阿多的百分比是多少。

【问题讨论】:

  • 看看collections.Counter-class。

标签: python dictionary key


【解决方案1】:

考虑

from collections import Counter

cnt = Counter(lst)
print {gender: {name: cnt[name] for name in persons if persons[name] == gender}
          for gender in set(persons.values())}

# {'Eunuch': {'Varys': 1}, 
# 'Male': {'Tyrion': 3, 'Hodor': 2, 'Theon': 0}, 
# 'Female': {'Daenerys': 2, 'Arya': 1, 'Sansa': 0}}

为了计算百分比,让我们添加一个辅助函数:

def percentage_dict(d):
    s = float(sum(d.values()))
    return {k: 100 * v / s for k, v in d.items()}

然后

print {gender: percentage_dict({name: cnt[name] for name in persons if persons[name] == gender})
       for gender in set(persons.values())}

# {'Eunuch': {'Varys': 100.0}, 'Male': {'Hodor': 40.0, 'Theon': 0.0, 'Tyrion': 60.0}, 'Female': {'Daenerys': 66.66666666666667, 'Arya': 33.333333333333336, 'Sansa': 0.0}}

这就是如何使用辅助函数更有效地编写这种理解:

def invert(d):
    """Turn {a:x, b:x} into {x:[a,b]}"""
    r = {}
    for k, v in d.items():
        r.setdefault(v, []).append(k)
    return r

然后

cnt = Counter(lst)
print {gender: {name: cnt[name] for name in names}
       for gender, names in invert(persons).items()}

排除总和为零的子项

print {gender: {name: cnt[name] for name in names}
    for gender, names in invert(persons).items()
    if any(cnt[name] for name in names)
}

【讨论】:

  • +1 因为它很短,而且对于嵌套的单行字典理解,它几乎可读性很好
  • 太美了。如果您想知道与所有男性相比,“Hodor”提到的百分比是多少,这段代码中是否有任何简单的方法来操作 Counter。所以名字的计数是性别的浮动百分比。
  • @thg435 非常感谢。我对这个网站的响应速度感到非常惊讶。我希望在未来,我能像你一样乐于助人!
  • @donstone666:不客气……欢迎来到 SO! ;)
  • @thg435 我注意到了一件小事。当我从 lst 中删除 Varys 时。无论如何都会出现性别太监,这似乎是不必要的。如何处理?编辑:因为当没有那个性别的人提到那个好percentage_dict(d) 会被零除:)
【解决方案2】:
from collections import defaultdict

gender = {
    'Hodor' : 'Male',
    'Tyrion': 'Male',
    'Theon': 'Male',
    'Arya': 'Female',
    'Daenerys': 'Female',
    'Sansa': 'Female',
    'Varys': 'Eunuch'
}

lst = ['Hodor', 'Hodor', 'Tyrion', 'Tyrion', 'Tyrion', 'Arya', 'Daenerys', 'Daenerys', 'Varys']

result = defaultdict(lambda: defaultdict(int))
for name in lst:
    result[gender[name]][name] += 1

【讨论】:

  • 是的,但是如何获得{Theon:0}
  • for name, g in gender.iteritems(): result[g][name] = lst.count(name)??
猜你喜欢
  • 2022-01-25
  • 1970-01-01
  • 2016-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多