使用另一个列表作为“过滤器”对python中的dicts列表进行排序?

时间:2011-07-13 22:28:20

标签: python dictionary

b = [{'id': 'a'}, {'id': 'c'}, {'id': 'b'}, {'id': 'e'}]

我需要这个成为:

b = [{'id': 'a'}, {'id': 'c'}, {'id': 'e'}, {'id': 'b'}]

此新订单由另一个列表定义。

my_filter = ['a', 'c', 'e', 'b']

...正如您所看到的,带有dicts的列表现在具有一系列在my_filter变量上显示的ID。

我能够重新排序,但是使用一堆fors并不会有效率。你知道更好的方法吗?我已经知道如何sort a list of dictionaries by values of the dictionary,但我需要这个顺序由另一个列表定义。

编辑my_filter被命名为filter,我在Dave Kirby's recommendation后更改,因为它是内置的。由于某些答案中仍有filter,因此如果您在某些答案中看到filter,则可以避免混淆。

5 个答案:

答案 0 :(得分:7)

>>> sorted(b, key=lambda x: filter.index(x['id']))
[{'id': 'a'}, {'id': 'c'}, {'id': 'e'}, {'id': 'b'}]

答案 1 :(得分:5)

请记住,Ignacio的解决方案等同于执行您想要避免的嵌套for循环。即它是n ^ 2。更有效的解决方案如下:

>>> filterdict = dict((k,i) for i,k in enumerate(filter))
>>> sorted(b, key=lambda x: filterdict[x['id']])
[{'id': 'a'}, {'id': 'c'}, {'id': 'e'}, {'id': 'b'}]

或:

>>> b.sort(key=lambda x: filterdict[x['id']])
>>> b
[{'id': 'a'}, {'id': 'c'}, {'id': 'e'}, {'id': 'b'}]

就地排序。

编辑: antonakos'解决方案是最好的(2n),如果你的id是唯一的(这可能是一个安全的假设,但你没有指定,所以我不想假设)。这是一种稍微简短的写作方式,以防它更清晰:

>>> d = dict((i['id'], i) for i in b)
>>> [d[key] for key in filter]
[{'id': 'a'}, {'id': 'c'}, {'id': 'e'}, {'id': 'b'}]

答案 2 :(得分:3)

构建反向字典并查找过滤器序列的值:

def order_by_values_for_key(key, dictionaries, values):
    rev = {}
    for d in dictionaries:
        val = d[key]
        rev[val] = d

    return [ rev[val] for val in values ]

b = [{'id': 'a'}, {'id': 'c'}, {'id': 'b'}, {'id': 'e'}]
filter = ['a', 'c', 'e', 'b']
print order_by_values_for_key('id', b, filter)

使用Python3的字典理解你可以写:

def order_by_values_for_key(key, dictionaries, values):
    rev = { d[key] : d for d in dictionaries }
    return [ rev[val] for val in values ]

答案 3 :(得分:3)

order = dict((v, i) for (i,v) in enumerate(filter))
sorted(b, key=lambda x:order[x['id']])

这应该比Ignacio的答案更有效,因为字典查找是O(1)而索引(x)是O(n)。

BTW过滤器是内置函数的名称,因此不应将其用作变量名。

答案 4 :(得分:1)

要添加到antonakos和Keither的答案(我没有代表直接评论),字典理解也可以在2.7中获得,并且在这个例子中大约快1/3:

python -mtimeit "{k: i for i,k in enumerate(range(1000))}"
10000 loops, best of 3: 93.5 usec per loop

python -mtimeit "dict((k,i) for i,k in enumerate(range(1000)))"
10000 loops, best of 3: 158 usec per loop