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

根据Python中的另一个dict列表对dict列表进行排序,python,arrays,dictionary,Python,Arrays,Dictionary,我有两张单子 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中,而将A的对象值重写为零。我想保留A的值,但按B的顺序排序 我如何做到这一点?您更喜欢Python的解决

我有两张单子

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中,而将A的对象值重写为零。我想保留A的值,但按B的顺序排序


我如何做到这一点?您更喜欢Python的解决方案,这个怎么样?在
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%,空间复杂度提高了一倍。

您可以将键的索引存储在字典中,并使用中的索引。这将在
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'}]

平均病例线性时间。将每个dict直接放入需要的位置,无需缓慢的
索引
调用,甚至无需调用
排序

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

  • 将列表
    A
    合并到单个查找目录中
  • 根据
    B
    中的顺序构建一个新列表,使用lookup dict查找与每个键匹配的值
  • 代码:


    如果需要,您可以保留
    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)]
    

    为什么你会有一个单键的单键目录?这听起来像是一个一阶dict的作业,或者可能是一个元组列表。所有这些
    索引
    调用使其总体上以二次时间运行。@user2357112在O(n)时间内找到了一个更好的解决方案。而不是O(n),因为它调用的是
    排序
    。不过还是比O(n**2)强。是的,它是
    O(n log(n))
    。但是,对于小输入,使用
    sorted()
    可能比纯Python的
    O(n)
    解决方案快。
    sum
    是连接列表的一种非常糟糕的(二次时间)方法。但是,从A构建查找表,然后在传递B中使用它,比我使用从B构建的查找表并在传递A中使用的查找表要好。使用
    itertools
    调用得不错。我认为,
    chain.from_iterable
    将使列表变得平坦。谢谢你的编辑。啊,哎呀。我一直忘了。谢谢你提醒我。
    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'}]
    
    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)]