根据Python中的另一个dicts列表对dicts列表进行排序

时间:2017-07-21 18:32:00

标签: python arrays dictionary

我有2个列表

A = [{'g': 'goal'}, {'b': 'ball'}, {'a': 'apple'}, {'f': 'float'}, {'e': 'egg'}]
B = [{'a': None}, {'e': None}, {'b': None}, {'g': None}, {'f': None}]

我想根据B对A进行排序。我之所以这样说的原因是,我不能简单地将B的内容复制到A中并使用None覆盖A的对象值。我想保留A的值,但是按照B的顺序对它进行排序。

我如何实现这一目标?更喜欢Python中的解决方案

4 个答案:

答案 0 :(得分:2)

spots = {next(iter(d)): i for i, d in enumerate(B)}
sorted_A = [None] * len(A)
for d in A:
    sorted_A[spots[next(iter(d))]] = d

平均情况线性时间。将每个字典直接放入需要去的地方,无需index个慢速呼叫,甚至可以调用sorted

答案 1 :(得分:1)

这个怎么样?在A上创建查找词典,然后使用B的键以正确的顺序创建新列表。

In [103]: lookup_list = {k : d for d in A for k in d}

In [104]: sorted_list = [lookup_list[k] for d in B for k in d]; sorted_list
Out[104]: [{'a': 'apple'}, {'e': 'egg'}, {'b': 'ball'}, {'g': 'goal'}, {'f': 'float'}]

性能

设定:

import random
import copy

x = list(range(10000)) 
random.shuffle(x)

A = [{str(i) : 'test'} for i in x] 
B = copy.deepcopy(A)
random.shuffle(B)

# user2357112's solution
%%timeit
spots = {next(iter(d)): i for i, d in enumerate(B)}
sorted_A = [None] * len(A)
for d in A:
    sorted_A[spots[next(iter(d))]] = d

# Proposed in this post
%%timeit
lookup_list = {k : d for d in A for k in d}
sorted_list = [lookup_list[k] for d in B for k in d]; sorted_list

结果:

100 loops, best of 3: 9.27 ms per loop
100 loops, best of 3: 4.92 ms per loop

原始O(n)加速45%,空间复杂度增加一倍。

答案 2 :(得分:1)

您可以将键的索引存储在字典中,并使用sorting function中的键。这可以在O(n log(n))时间内完成:

>>> keys = {next(iter(v)): i for i, v in enumerate(B)}
>>> keys
{'a': 0, 'e': 1, 'b': 2, 'g': 3, 'f': 4}    
>>> A.sort(key=lambda x: keys[next(iter(x))])
>>> A
[{'a': 'apple'}, {'e': 'egg'}, {'b': 'ball'}, {'g': 'goal'}, {'f': 'float'}]

答案 3 :(得分:1)

您可以通过迭代B中的现有有序键来避免排序:

  1. 将列表A合并到一个查找字典
  2. 根据B中的订单构建新列表,使用查找字典查找与每个键匹配的值
  3. 代码:

    import itertools
    
    merged_A = {k: v for d in A for k, v in d.items()}
    sorted_A = [{k: merged_A[k]} for k in itertools.chain.from_iterable(B)]
    # [{'a': 'apple'}, {'e': 'egg'}, {'b': 'ball'}, {'g': 'goal'}, {'f': 'float'}]
    

    如果需要,您可以保留A中的原始dict对象,而不是构建新的对象:

    keys_to_dicts = {k: d for d in A for k in d}
    sorted_A = [keys_to_dicts[k] for k in itertools.chain.from_iterable(B)]