簡體   English   中英

根據Python中的另一個字典列表對字典列表進行排序

[英]Sorting a list of dicts based on another list of dicts in Python

我有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解決方案

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調用。

這個怎么樣? 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'}]

您可以通過遍歷B現有的有序鍵來避免排序:

  1. 將列表A合並為單個查詢字典
  2. 使用查找字典從B的順序構建新列表,以找到與每個鍵匹配的值

碼:

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)]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM