【问题标题】:python dictionary values sortingpython字典值排序
【发布时间】:2011-08-28 02:40:58
【问题描述】:

我有 2 个字典,dict1dict2,它们包含相同的键,但键的值不同。我想要做的是对每个字典,从最大到最小对值进行排序,然后给每个值一个 1-N 的等级,1 是最大值。从这里,我想获得每个字典中相同键的值的等级差异。例如:

dict1 = {a:0.6, b:0.3, c:0.9, d:1.2, e:0.2}
dict2 = {a:1.4, b:7.7, c:9.0, d:2.5, e:2.0}

# sorting by values would look like this:
dict1 = {d:1.2, c:0.9, a:0.6, b:0.3, e:0.2}
dict2 = {c:9.0, b:7.7, d:2.5, e:2.0, a:1.4}

#ranking the values would produce this:
dict1 = {d:1, c:2, a:3, b:4, e:5}
dict2 = {c:1, b:2, d:3, e:4, a:5}

#computing the difference between ranks would be something like this:
diffs = {}
for x in dict1.keys():
    diffs[x] = (dict1[x] - dict2[x])

#diffs would look like this:
diffs[a] = -2
diffs[b] = 2
diffs[c] = 1
diffs[d] = -2
diffs[e] = 1

我知道字典是随机的且不可排序的,但也许有一种方法可以将键和值放入列表中?我面临的主要挑战是获取按值(从大到小)排序的键和值,然后将值更改为其在排序列表中的相应排名。

【问题讨论】:

    标签: python sorting dictionary


    【解决方案1】:

    小字典的简单解决方案是

    dict1 = {"a":0.6, "b":0.3, "c":0.9, "d":1.2, "e":0.2}
    dict2 = {"a":1.4, "b":7.7, "c":9.0, "d":2.5, "e":2.0}
    k1 = sorted(dict1, key=dict1.get)
    k2 = sorted(dict2, key=dict2.get)
    diffs = dict((k, k2.index(k) - k1.index(k)) for k in dict1)
    

    一个更高效、可读性更强的版本,适用于更大的字典:

    ranks1 = dict(map(reversed, enumerate(sorted(dict1, key=dict1.get))))
    ranks2 = dict(map(reversed, enumerate(sorted(dict2, key=dict2.get))))
    diffs = dict((k, ranks2[k] - ranks1[k]) for k in dict1)
    

    【讨论】:

    • +1。没有多少人以这种方式使用mapreversed。棘手:-) 但我建议使用itertools.imap 来节省一些内存。
    • 同意。通常,出于性能原因,我建议在 map 上使用列表推导或生成器表达式(直到现在才知道 imap),但我认为这是一个更好、更易读的解决方案。荣誉:-)
    • sorted(dict1.items(), key=lambda item: item[1]) 会不会更快,因为这样您就不需要查找字典中的每个值了?
    • @Aleksi:首先,字典查找非常快。我认为sorted(dict1, key=dict1.get) 更快,因为您没有为每个项目调用 Python 函数的开销。当然你的表达式可以写成sorted(dict1.items(), key=operator.itermgetter(1)),去掉lambda函数并使这个参数无效。但其次,您的表达式返回的列表与我的不同。我需要以某种方式摆脱这些价值观。
    • @Sven:是的,我在想dict((key, rank) for rank, (key, value) in enumerate(sorted(dict1.items(), key=operator.itemgetter(1)))) 中的一些东西,但是如果列表理解比map+reversed 慢,我的观点确实没有实际意义。跨度>
    【解决方案2】:

    您可能对collections.OrderedDict感兴趣

    这是一个示例,我最初的想法是您还在寻找具有按值排序的键的字典,od1od2 是。

    d1 = {"a":0.6, "b":0.3, "c":0.9, "d":1.2, "e":0.2}
    d2 = {"a":1.4, "b":7.7, "c":9.0, "d":2.5, "e":2.0}
    
    od1 = OrderedDict(sorted(d1.items(), key=lambda t: t[1]))
    od2 = OrderedDict(sorted(d2.items(), key=lambda t: t[1]))
    
    k1 = od1.keys()
    k2 = od2.keys()
    
    diff = dict((k, n - k2.index(k)) for n, k in enumerate(k1))
    

    如果您不需要它们,那么 Sven 解决方案可能会更快。

    编辑:说实话没那么快...(sven.py 是他的第二个更高效的版本):

    $ cat /tmp/mine.py | time python -m timeit
    10000000 loops, best of 3: 0.0842 usec per loop
    real    0m 3.69s
    user    0m 3.38s
    sys 0m 0.03s
    $ cat /tmp/sven.py | time python -m timeit
    10000000 loops, best of 3: 0.085 usec per loop
    real    0m 3.86s
    user    0m 3.42s
    sys 0m 0.03s
    

    如果有人想发布更大的格式化字典,我也会对其进行测试。

    【讨论】:

    • 这是错误的工作工具,提问者并不真正需要有序字典,他只需要一种对值进行排序的方法。
    • Asker 说:我面临的主要挑战是获取按值排序的键和值OrderedDict 在我看来是正确的工具
    • 我看不出OrderedDict 如何简化生成diffs 字典的任务。你能举一个完整的例子吗? (顺便说一句,不是我的反对票。)
    • 是的,但是看问题。首先你有字典,然后你需要得到值的排名(你不需要有序的字典),然后你想要最终字典中的排名结果。您在任何地方都需要有序字典,它们是适合这项工作的错误工具。例如,看看 Svens 的回答。
    【解决方案3】:

    你用的是什么版本的python?如果是 2.7,请使用 OrderedDict。

    根据 Python 2.7 docs:

    OrderedDict(sorted(d.items(), key=d.get))
    

    如果您使用的是 Python 2.4-2.6,您仍然可以通过从 pypi here 安装 OrderedDict 来使用它,或者如果您有 setuptools,请运行

    easy_install ordereddict
    

    【讨论】:

    • 同意!特别是因为我们的两个答案都是完全有效的解决方案。我也对你的投票表示赞同,以否定做这件事的人的行为。
    • 我没有投反对票,但我认为OrderedDict 在这里没有任何帮助。要实现 OP 想要的,您不需要实际对字典进行排序。而且,你给的key函数是错误的。
    • 哦该死的,你说得对关键功能。我只是直接从文档中复制/粘贴...将编辑。
    【解决方案4】:

    字典不是解决这个问题的正确数据结构。您应该尽快转换为排序列表并仅生成字典作为最终结果。以下示例解决方案尽可能使用迭代器和生成器表达式,以避免在此过程中创建过多(可能很大)的帮助器列表:

    def get_ranking(vals):
        '''Return a list of pairs: (key, ranking), sorted by key.'''
        ranking = sorted(((v, k) for k, v in vals.iteritems()), reverse=True)
        return sorted((k, i) for (i, (_v, k)) in enumerate(ranking))
    
    def ranking_diff(rank1, rank2):
        return dict((k, v1 - v2) for (k, v1), (_, v2) in itertools.izip(rank1, rank2))
    
    def get_diffs(dict1, dict2):
        r1 = get_ranking(dict1)
        r2 = get_ranking(dict2)
        return ranking_diff(r1, r2)
    
    print get_diffs(dict1, dict2)
    # prints: {'a': -2, 'c': 1, 'b': 2, 'e': 1, 'd': -2}
    

    请注意,此解决方案假定两个 dicts 包含完全相同的键。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-01
      • 2014-06-24
      • 2021-08-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多