【问题标题】:Python OrderedDict: sort by tuple order?Python OrderedDict:按元组顺序排序?
【发布时间】:2015-05-28 19:34:57
【问题描述】:

所以我有这本字典,我正在将其转换为 OrderedDict。在转换时,我想按其键出现在单独元组中的顺序对 OrderedDict 进行排序。我想附加到 OrderedDict 末尾的任何其他值。应该忽略排序元组中不存在的键。

我想我已经掌握了大部分,但我无法将我的大脑包裹在 lambda 排序函数上。你能帮我解决掉吗?

from collections import OrderedDict

d = {
    'spam': 'tasty',
    'subtitle': 'A Subtitle',
    'title': 'Test Title',
    'foo': 'bar',
}

key_order = ('title', 'subtitle', 'non_in_dictionary')
ordered_dict = OrderedDict(sorted(d.items(), key=lambda ???? ))

应该产生ordered_dict:

{
    'title': 'Test Title',
    'subtitle': 'A Subtitle',
    'spam': 'tasty',
    'foo': 'bar',
}

【问题讨论】:

  • 对于不在 key_order 元组中的键,您打算按什么顺序排列?
  • @jonrsharpe,我的问题是我不知道要尝试什么;我很茫然。
  • @tzaman,我不挑剔。我想是按字母顺序排列的。我实际上是从 JSON 文件中引入数据(具有固有顺序,尽管 JSON 不关心),因此我将 spam 放在 foo 之前。
  • @niteshade 只是看到你提到 我实际上是从 JSON 文件中引入数据 - 看看在加载 JSON 时使用 object_pairs_hook - 见 this post举些例子。如果您知道您的属性在 JSON 数据中的顺序正确,那将是一个更有效的解决方案。
  • @JonClements,非常感谢,看起来不错。我会记住这一点,以备将来参考。大多数 JSON 元素的顺序都是正确的,但我仍然需要将一些元素拉到顶部,所以无论如何我都会进行一些排序。无论如何,我真的很感激。

标签: python


【解决方案1】:

另一种比排序更简单的方法是从标题创建OrderedDict,然后从原始dict 更新OrderedDict

from collections import OrderedDict

d = {
    'spam': 'tasty',
    'subtitle': 'A Subtitle',
    'title': 'Test Title',
    'foo': 'bar',
}

key_order = ('title', 'subtitle')
od = OrderedDict((k, d[k]) for k in key_order)
od.update(d)

或者正如 tzaman 在 cmets 中所建议的那样,因为这些值将始终在以下更新中设置,您可以使用以下方法构造原始 OrderedDict

od = OrderedDict.fromkeys(key_order)
od.update(d)

【讨论】:

  • 简单一点:od = OrderedDict.fromkeys(key_order) -- 值无关紧要。
  • @niteshade:它不应该明显变慢;如果有的话,我希望它会更快。
  • @niteshade 字典更新速度很快 - 我个人希望它能够执行创建索引查找,然后使用 lambda 针对该查找对 dicts 项进行排序......从而创建一个 @ 987654330@ 被放入 OD 中。如果key_order 是原始dict 的一个大子集,那么它们将是不必要的替换 - 但这将是关键更新,因此应该快速并避免创建列表的内存成本。
  • @niteshade 这几乎肯定会更快,尤其是使用fromkeys 公式。第一遍只设置键顺序,第二遍将遍历你的源字典一次;根本没有排序,所以理论上它将是O(n) 而不是O(n lg n),这对于巨大的字典来说是一个巨大的胜利。 sorted 还将创建一个内存不好的中间副本。
  • @niteshade od = OrderedDict.fromkeys(filter(d.__contains__, key_order))。或者在原版中:od = OrderedDict((k, d[k]) for k in key_order if k in d)
【解决方案2】:
ordered_dict = OrderedDict(sorted(dict.items(),
               key=lambda x: key_order.index(x[0])if x[0] in key_order else 10e10 ))

这使用键顺序中给定项目的索引键。如果没有找到,它会使用一个大数字,把它放在最后。它产生以下OrderedDict

OrderedDict([('title', 'Test Title'), ('subtitle', 'A Subtitle'), ('foo', 'bar'), ('spam', 'tasty')])

foospam 之前,因为原始字典的顺序是任意的。

【讨论】:

    【解决方案3】:
    from collections import OrderedDict
    
    d = {
        'spam': 'tasty',
        'subtitle': 'A Subtitle',
        'title': 'Test Title',
        'foo': 'bar',
    }
    
    key_order = ('title', 'subtitle')
    key_order = OrderedDict((k, i) for i, k in enumerate(key_order))
    ordered_dict = OrderedDict(sorted(d.iteritems(), key=lambda k: key_order.get(k[0], float("inf"))))
    

    在 python 3 中使用 items() 而不是 iteritems()

    【讨论】:

    • 这会产生错误。 key_ordertuple,因此没有方法 get
    • @TigerhawkT3 仔细看看。 key_orderOrderedDict
    • @TigerhawkT3 那部分很好,他们正在将其转换为下一行的OrderedDict,问题是语法错误。
    • k, i周围添加括号。
    • 我也会使用 float('inf') 而不是 sys.maxint 但由于容器的大小不会超过这个值 - 这更多的是风格问题 - 我只是倾向于发现它更明确我真的是说在一切之后其他
    猜你喜欢
    • 2017-12-05
    • 2011-10-04
    • 2017-12-21
    • 2013-05-18
    • 2017-04-19
    • 2019-09-01
    • 2013-03-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多