Python 如何根据另一个列表对元组列表进行排序

Python 如何根据另一个列表对元组列表进行排序,python,list,sorting,Python,List,Sorting,有一份清单: a = [("ax", 1), ("ec", 3), ("bk", 5)] 另一份名单: b = ["ec", "ax", "bk"] 我想根据b对a进行排序: sort_it(a, b) a = [("ec", 3), ("ax", 1), ("bk", 5)] 如何做到这一点 a.sort(key=lambda x: b.index(x[0])) 这将使用a中每个元组的第一个元素b中的索引作为排序依据,对a进行就地排序 另一种可能更干净的书写方式是: a.sort(k

有一份清单:

a = [("ax", 1), ("ec", 3), ("bk", 5)]
另一份名单:

b = ["ec", "ax", "bk"]
我想根据
b
a
进行排序:

sort_it(a, b)

a = [("ec", 3), ("ax", 1), ("bk", 5)]
如何做到这一点

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]

另一种可能性是排序
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),因此对于较大的列表,这仍然是可扩展的

可能不需要传统的排序

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

实际上有一种方法可以在线性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]
    
  • 如果将任何列表元素映射到不存在于
    所需顺序中的键,则这些元素将被自动丢弃。例如:

    >>> sorted_by([1, 2, 3], [1, 2, 3], key=lambda x: 5)
    []
    
另见:


@jpp事实上,这不是一个复制品。这个问题是关于对齐一个列表与另一个列表的顺序,而另一个问题是关于使用第二个列表的值作为第一个列表的排序键。尝试一下这里给出的解决方案,你会发现它不会产生预期的结果。同样,如果您尝试将此处接受的解决方案应用到案例中,您将得到一个
ValueError
@aryehleibtaulog,我很欣赏这种情绪,因此我再次打开了它。在我看来,它们都是相互适应的。如果一种解决方案被理解,那么另一种解决方案是显而易见的。我们不想走的路是,我们有一个单独的解决方案,用于len-2元组、len-3元组、len-4元组等。这是不好的,因为有2个for循环。For循环在Python中是不好的。最好使用lambda函数“Bad”可能不是真的。一般来说,嵌套循环的时间复杂度可能为O(n^2),但列表理解在Python中是有效的,尤其是对于OP这样的小输入。在这种情况下,“.”此外,我认为Python的创建者会不同意您对lambdas的看法,正如他所声称的那样。Python的for循环是一种不好的排序方式我明白了:(
TypeError:unhabable type:'list'
我不喜欢这个答案,因为它非常专用于按照元组的第一个元素对元组进行排序,并且根本不清楚如何将此解决方案推广到其他场景中。任意长度的元组排序代码还假设每个元组都有唯一的第一个元素元素;如果任意两个元组具有相同的第一个元素,则其中一个元组将被静默丢弃。这很好,但如果元组列表的长度超过所需的顺序,该怎么办?