有一个清单:
a = [("ax", 1), ("ec", 3), ("bk", 5)]
另一个清单:
b = ["ec", "ax", "bk"]
我想a
根据b
:
sort_it(a, b)
a = [("ec", 3), ("ax", 1), ("bk", 5)]
这该怎么做?
a.sort(key=lambda x: b.index(x[0]))
这使用每个元组的第一个元素a
的索引 in 作为它排序的值,就地排序。b
a
另一种可能更简洁的书写方式是:
a.sort(key=lambda (x,y): b.index(x))
如果您有大量项目,则以不同的方式做事可能会更有效,因为.index()
在长列表上可能是一项昂贵的操作,并且您实际上不需要进行完整排序,因为您已经知道顺序:
mapping = dict(a)
a[:] = [(x,mapping[x]) for x in b]
请注意,这仅适用于 2 元组列表。如果您希望它适用于任意长度的元组,则需要稍微修改它:
mapping = dict((x[0], x[1:]) for x in a)
a[:] = [(x,) + mapping[x] for x in b]
另一种可能性是排序a
,b
根据索引排序,然后根据索引b
排序。a
a.sort(key=lambda x: x[0])
ind = [i[0] for i in sorted(enumerate(b),key=lambda x: x[1])]
a = [i[0] for i in sorted(zip(a,ind),key=lambda x: x[1])]
因为每次排序都需要 n*log(n) 这对于更大的列表仍然是可扩展的
实际上有一种方法可以在线性 O(n) 时间内做到这一点,因为这并不是真正的排序操作。列表的存在b
意味着排序已经完成;我们真正需要做的就是将 的元素重新排列成a
相同的顺序。多亏了字典,这可以有效地完成。
from collections import defaultdict
def sorted_by(seq_to_sort, desired_order, key=None):
if key is None:
key = lambda x: x
# group the elements by their key
grouped_items = defaultdict(list)
for item in seq_to_sort:
k = key(item)
grouped_items[k].append(item)
# flatten the dict of groups to a list
return [item for key in desired_order for item in grouped_items[key]]
用法:
a = [("ax", 1), ("ec", 3), ("bk", 5)]
b = ["ec", "ax", "bk"]
result = sorted_by(a, b, lambda tup: tup[0])
print(result) # output: [("ec", 3), ("ax", 1), ("bk", 5)]
笔记:
这是一个稳定的排序;如果两个列表项具有相同的键,则它们的顺序将被保留。例子:
>>> sorted_by([1, 2, 3], [5], key=lambda x: 5)
[1, 2, 3]
如果任何列表元素映射到 中不存在的键,则desired_order
这些元素将被静默丢弃。例如:
>>> sorted_by([1, 2, 3], [1, 2, 3], key=lambda x: 5)
[]
也可以看看:
可能不需要传统的排序。
[tup for lbl in b for tup in a if tup[0] == lbl]
# [('ec', 3), ('ax', 1), ('bk', 5)]