我试图根据list2 = ['four','six','two','three','one','five']
对list1 = [4,6,2,3,1,5]
进行排序,以便我的代码更新list2
到
['one', 'two', 'three', 'four', 'five', 'six']
。
我尝试了以下代码:
list2.sort(key = lambda x: list1[list2.index(x)])
但它会出现以下错误:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
ValueError: 'four' is not in list
但是,使用sorted()
函数执行相同操作并将list2
更新为已排序列表可提供所需的结果。为什么呢?
答案 0 :(得分:1)
在list.sort
期间,实例的行为就像它不包含任何内容一样。这意味着您不应在key
函数中使用该列表实例。
您可以使用以下脚本验证:
a = [3,2,1]
def printlist(key):
print(a)
return key
print('before sorting', a)
a.sort(key=printlist)
print('after sorting', a)
打印哪些:
before sorting [3, 2, 1]
[]
[]
[]
after sorting [1, 2, 3]
在CPython中可以看到相应的代码here。我在这里复制了该部分之前的评论,因为它包含了这个理由:
/* The list is temporarily made empty, so that mutations performed
* by comparison functions can't affect the slice of memory we're
* sorting (allowing mutations during sorting is a core-dump
* factory, since ob_item may change).
*/
基本上它表示列表中的任何突变都可能导致段错误,并且因为key
函数可以执行任意代码,列表将被清空。
这也是直接修改导致错误的原因:
a = [3,2,1]
def appendelement(item):
a.append(item)
return item
a.sort(key=appendelement)
ValueError:在排序
期间修改的列表
sorted
只能解决该问题,因为它会立即复制列表(related CPython code),因此“副本”会被排序。这意味着原始的list2
仍然完整无缺,可以使用。
请注意,因为list.index
你的函数O(n)基本上变成N ** 2而不是N * log(N)。
Python wiki包含一个关于decorate-sort-undecorate方法的部分,通常用于这些情况:
list2 = ['four','six','two','three','one','five']
list1 = [4,6,2,3,1,5]
decorated = [(num, i, name) for i, (num, name) in enumerate(zip(list1, list2))]
decorated.sort()
undecorated = [name for _, _, name in decorated]
print(undecorated)
# ['one', 'two', 'three', 'four', 'five', 'six']
来自i
的{{1}}主要用于避免每次比较名称 - 因为enumerate
总是不同的。在这种情况下可以省略它。
此处您还有一个独特的映射,因此您也可以使用翻译词典:
i
答案 1 :(得分:0)
使用标准库zip函数逐个元素地组合两个列表。对组合列表进行排序,这将有效地导致第一个列表成为排序字段。然后理解恢复现在排序的list2。
list1 = [4,6,2,3,1,5]
list2 = ['four','six','two','three','one','five']
list2 = [a[1] for a in sorted(zip(list1, list2))]
print(list2)
>>> ['one', 'two', 'three', 'four', 'five', 'six']