我的两个清单列表是:
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_1
(lst_2
)子列表中的第二个值排序lst_2[i][1]
的最有效方法是什么?
首选输出:
[[2, 'Mcquin'], [4, 'Paul'], [1, 'John'], [9, 'Coco'], [7, 'Jimmy'], [11, 'Coco']]
如果存在相同名称的重复项(在这种情况下为Coco),则无关紧要。此外,列表将始终包含与此处相同的名称。
答案 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
都是一个名称,每个值都是 { {3}}(感谢RoadRunner)与该名称对应的数字。list
通过使用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中存在的值,则会产生错误(可能是合理的,因为缺少密钥)。