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

时间:2018-02-15 10:44:06

标签: python python-3.x sorting

我的两个清单列表是:

lst_1 = [[1, 'John'], [2, 'Mcquin'], [4, 'Paul'], [7, 'Jimmy'], [9, 'Coco'], [11, 'Coco']]
lst_2 = [[3, 'Mcquin', 1], [6, 'Paul', 6], [5, 'John', 15], [12, 'Coco', 18], [8, 'Jimmy', 24], [10, 'Coco', 24]]

根据lst_1lst_2)子列表中的第二个值排序lst_2[i][1]的最有效方法是什么? 首选输出:

[[2, 'Mcquin'], [4, 'Paul'], [1, 'John'], [9, 'Coco'], [7, 'Jimmy'], [11, 'Coco']]

如果存在相同名称的重复项(在这种情况下为Coco),则无关紧要。此外,列表将始终包含与此处相同的名称。

5 个答案:

答案 0 :(得分:4)

如果两个列表的名称相同,则可以将每个元素的索引存储在collections.defaultdict中,然后弹出每个索引,并在排序过程中找到项目时将其用作排序键。

<强>演示:

from collections import defaultdict, deque

lst_1 = [[1, 'John'], [2, 'Mcquin'], [4, 'Paul'], [7, 'Jimmy'], [9, 'Coco'], [11, 'Coco']]
lst_2 = [[3, 'Mcquin', 1], [6, 'Paul', 6], [5, 'John', 15], [12, 'Coco', 18], [8, 'Jimmy', 24], [10, 'Coco', 24]]

sort_map = defaultdict(deque)
for i, x in enumerate(lst_2):
    sort_map[x[1]].append(i)

result = sorted(lst_1, key=lambda x: sort_map[x[1]].popleft())

print(result)

<强>输出:

[[2, 'Mcquin'], [4, 'Paul'], [1, 'John'], [9, 'Coco'], [7, 'Jimmy'], [11, 'Coco']]. 

注意:您可以使用collections.deque以固定时间从头开始弹出元素,如上所示。这种微小的改进允许上述解决方案保持在整体O(NlogN),这是分拣的成本。

答案 1 :(得分:2)

编辑:我认为我有一个 O(n) 解决方案!

最初,我认为我们可以根据dictionary创建一个lst_2名称及其应该出现在最终列表中的索引。然后我们可以通过排序lst_1来创建最终列表 - 提供O(n log(n))解决方案。

然而,该方法的问题是lst_2中存在重复的名称!此外,这种新方法甚至具有更好的时间复杂度!

首先,我们根据lst_1 创建一个字典,其中每个key都是一个名称,每个值都是 list { {3}}(感谢RoadRunner)与该名称对应的数字。

通过使用deque,我们维护lst_1中具有相同名称的元素的顺序。此外,我们还可以在.popleft时间内deque致电O(1)

这允许我们迭代lst_2(不需要任何排序,因为它已经按顺序排列)并在新列表中附加名称,后跟我们创建的字典中的第一个值条目。

如果我们使用.popleft()来获取第一个元素,我们也会将其删除,这意味着当lst_2中出现该名称时,我们会在lst_1中获得下一个值。

所以,这是代码:

import collections
vals = {}
for v, n in lst_1:
    vals.setdefault(n, collections.deque()).append(v)

#vals == {'Paul': [4], 'Coco': [9, 11], 'John': [1], 'Mcquin': [2], 'Jimmy': [7]}
#        (each key here ^^ is actually a deque but it's easier to see with lists)
r = []
for _,n,_ in lst_2:
    r.append([n, vals[n].popleft()])

r(结果)作为:

[['Mcquin', 2], ['Paul', 4], ['John', 1], ['Coco', 9], ['Jimmy', 7], ['Coco', 11]]

答案 2 :(得分:1)

非常不诡异,但仍然易于理解和工作:

lst_new = []
for item in lst_2:
    name = item[1]
    for item2 in lst_1:
        if name == item2[1]:
            lst_new.append(list.copy(item2))
            lst_1.remove(item2)
            #item2[1] = "" is also an option but it's worse for long inputs
            break

输出:

>>> lst_new
[[2, 'Mcquin'], [4, 'Paul'], [1, 'John'], [9, 'Coco'], [7, 'Jimmy'], [11, 'Coco']]

答案 3 :(得分:0)

给出两个清单:

xs = [[4, 'a'], [3, 'b'], [7, 'c'], [10, 'd']]
ys = [ 7, 3, 4, 10]

以下行按xs中的项目顺序对列表ys进行排序:

[x for y in ys for x in xs if x[0] == y]

结果:

>>> [x for y in ys for x in xs if x[0] == y]
[[7, 'c'], [3, 'b'], [4, 'a'], [10, 'd']]

答案 4 :(得分:0)

试试这个:

l = sorted(lst_1, key=lambda x: [i[2] for i in lst_2 if i[1] == x[1]][0])

说明:只有当第二个值与参数匹配时,我们才会使用来自lst_2的第3个值(i [2])进行排序(i [1] == x [1])。

请注意,如果lst_2中缺少lst_1中存在的值,则会产生错误(可能是合理的,因为缺少密钥)。