【问题标题】:reordering list of dicts arbitrarily in python在python中任意重新排序dicts列表
【发布时间】:2010-07-22 20:48:38
【问题描述】:

我有一个 4 个字典(总是 4 个)的列表,看起来像这样:

[{'id':'1','name':'alfa'},{'id':'2','name':'bravo'},{'id':'3','name':'charlie'},{'id':'4','name':'delta'}]

我确切地知道我想要它们的顺序,即:

2, 3, 1, 4

对它们重新排序的最简单方法是什么?

【问题讨论】:

  • 我想你会喜欢我的更新,我无法想象它会变得更简单。

标签: python list


【解决方案1】:

如果它总是四个,并且你总是知道顺序,就像这样:

lst = [{...},{...},{...},{...}]
ordered = [lst[1],lst[2],lst[0],lst[3]]

如果您打算按“id”对它们进行排序,请按此顺序:

ordered = sorted(lst, key=lambda d: [2,3,1,4].index(int(d['id'])))

请注意,index()O(n),但不需要您构建字典。所以对于小的输入,这实际上可能更快。在您的情况下,有四个元素,保证进行十次比较。使用timeit,这个 sn-p 的运行速度比 tokland 的基于字典的解决方案快 10%……但这并不重要,因为两者都不重要。

【讨论】:

  • 谢谢 - 忘了索引,我调用了第一个项目 1 等,因此它通过索引超出范围错误。
  • 这段代码不是为要排序的 lst 中的每个元素调用 list.index (O(n)) 吗?它不适用于大型列表。
  • @tokland :是的,它是O(n) 4 个元素。最多 16 个。我认为这值得一票否决...但他的问题已通过第一个解决方案解决。
  • @Stephen,我认为这是要走的路,投反对票但推理原因。但我很抱歉让你不高兴,但除非问题被编辑,否则我不能取消投票。哪个是第一个解决方案?亚历克斯·马泰利的?
  • @tokland :感谢您解释原因。你对我投了反对票,我并不难过......我只是想指出你正在争论一个具有恒定 4 个元素的渐近复杂性。渐近复杂度适用于较大(或可变大小)的输入,他保证 4 个元素。对于那么小的东西,避免构建 O(1) 数据结构通常更快。我添加了一条注释,说明这是线性的,但我对其进行基准测试时比您的解决方案更快。
【解决方案2】:

这是一个非常通用的函数来强制执行所需顺序(任何不在所需顺序中的键值都放在结果列表的末尾,以任意子顺序):

def ordered(somelist, wantedorder, keyfunction):
    orderdict = dict((y, x) for x, y in enumerate(wantedorder))
    later = len(orderdict)
    def key(item):
        return orderdict.get(keyfunction(item), later)
    return sorted(somelist, key=key)

你会把它当作

import operator
sortedlist = ordered(dictlist, ('2', '3', '1', '4'),
                     operator.itemgetter('id'))

【讨论】:

    【解决方案3】:

    一个非泛化的解决方案:

    lst = [{'id':'1','name':'alfa'},{'id':'2','name':'bravo'},{'id':'3','name':'charlie'},{'id':'4','name':'delta'}]
    order = ["2", "3", "1", "4"]
    indexes = dict((idfield, index) for (index, idfield) in enumerate(order))
    print sorted(lst, key=lambda d: indexes[d["id"]])
    # [{'id': '2', 'name': 'bravo'}, {'id': '3', 'name': 'charlie'}, {'id': '1', 'name': 'alfa'}, {'id': '4', 'name': 'delta'}]
    

    这里概括:

    def my_ordered(it, wanted_order, key):
        indexes = dict((value, index) for (index, value) in enumerate(wanted_order))
        return sorted(it, key=lambda x: indexes[key(x)])
    
    import operator  
    print my_ordered(lst, order, operator.itemgetter("id"))
    

    【讨论】:

    • 好吧,这似乎只是 Alex Martelli 的答案,没有考虑输入中的元素,但没有考虑wanted_order。
    【解决方案4】:
    the_list.sort(key=lambda x: (3, 1, 2, 4)[int(x["id"])-1])
    

    更新0

    一个新的更简单的答案

    the_list = [the_list[i - 1] for i in (2, 3, 1, 4)]
    

    这样 OP 可以看到他想要的排序,并且排序没有愚蠢,这里不需要。它可能也很快。

    【讨论】:

    • 我可能会补充一点,虽然这对某些人来说很复杂,但看看其他答案,这个答案可能更快更直接。
    • 数组 (3, 1, 2, 4) 使用 dicts 的id - 1 进行索引,以获得您请求的顺序。
    【解决方案5】:

    如果您想重新排序而不考虑字典的内容:

    >>> order = 2, 3, 1, 4
    >>> d = [{'id':'1','name':'alfa'},{'id':'2','name':'bravo'},{'id':'3','name':'charlie'},{'id':'4','name':'delta'}]
    >>> index = dict(enumerate(dd))
    >>> [index[i-1] for i in order]
    [{'id': '2', 'name': 'bravo'}, {'id': '3', 'name': 'charlie'}, {'id': '1', 'name': 'alfa'}, {'id': '4', 'name': 'delta'}]
    

    如果您想根据字典的'id' 进行排序:

    >>> sorted(d, key=lambda x: order.index(int(x['id'])))
    [{'id': '2', 'name': 'bravo'}, {'id': '3', 'name': 'charlie'}, {'id': '1', 'name': 'alfa'}, {'id': '4', 'name': 'delta'}]
    

    【讨论】:

      猜你喜欢
      • 2017-12-27
      • 1970-01-01
      • 2015-09-16
      • 1970-01-01
      • 1970-01-01
      • 2018-07-12
      • 1970-01-01
      • 2014-04-15
      • 2017-04-28
      相关资源
      最近更新 更多