如何根据另一个列表对列表进行排序?

时间:2012-10-10 08:01:25

标签: python list sorting

有一个清单:

a = [("ax", 1), ("ec", 3), ("bk", 5)]

另一个清单:

b = ["ec", "ax", "bk"]

我想根据a对<{1}}进行排序:

b

怎么做?

4 个答案:

答案 0 :(得分:60)

a.sort(key=lambda x: b.index(x[0]))

使用来自a的每个元组的第一个元素的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]

答案 1 :(得分:1)

另一个可能性是对a进行排序,根据bb的索引进行排序,然后根据索引对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),因此对于更大的列表

仍然是可扩展的

答案 2 :(得分:0)

可能不需要传统的排序。

[tup for lbl in b for tup in a if tup[0] == lbl]
# [('ec', 3), ('ax', 1), ('bk', 5)]

答案 3 :(得分:0)

实际上,有一种方法可以在线性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)
    []
    

另请参阅: