为什么 sort(with key) 函数不能按预期工作?

why does the sort(with key) function not work as intended?

# A function that returns the frequency of each value:
def myFunc(e):
     return cars.count(e)

cars = ['Ford', 'Ford', 'Ford', 'Mitsubishi','Mitsubishi', 'BMW', 'VW']

cars.sort(key=myFunc) 

print(cars)

输出:

['Ford', 'Ford', 'Ford', 'Mitsubishi', 'Mitsubishi', 'BMW', 'VW']

我的期望:

['BMW', 'VM', 'Mitsubishi', 'Mitsubishi', 'Ford', 'Ford', 'Ford']

计数:

Ford - 3
Mitsubishi - 2
BMW - 1
VM - 1

它应该按列表中计数的升序排序。

问题是您在关键函数中使用了 cars,但是 .sort 是 in-place。这导致 cars 在对关键函数的中间调用中不可靠。

如果我们在关键函数中打印cars,我们可以看到问题:

def myFunc(e):
    print(cars)
    return cars.count(e)


cars = ['Ford', 'Ford', 'Ford', 'Mitsubishi', 'Mitsubishi', 'BMW', 'VW']

cars.sort(key=myFunc)

这输出

[]
[]
[]
[]
[]
[]
[]

所以 cars.count 将 return 0 无论传递什么元素,列表将保留 其原始顺序 .

使用 sorted(...) 而不是 in-place:

def myFunc(e):
    return cars.count(e)


cars = ['Ford', 'Ford', 'Ford', 'Mitsubishi', 'Mitsubishi', 'BMW', 'VW']

cars = sorted(cars, key=myFunc)

print(cars)

这输出

['BMW', 'VW', 'Mitsubishi', 'Mitsubishi', 'Ford', 'Ford', 'Ford']

作为side-note,在这种情况下你可以直接使用cars.count,而不用定义包装函数:

cars = sorted(cars, key=cars.count)

这个问题是因为您在修改函数时引用了汽车。

如果您获得副本,则不会发生这种情况:

def myFunc(e):
     return cars.count(e)

cars = ['Ford', 'Ford', 'Ford', 'Mitsubishi','Mitsubishi', 'BMW', 'VW']

cars2 = cars.copy()

cars2.sort(key=myFunc) 

print(cars2)
# ['BMW', 'VW', 'Mitsubishi', 'Mitsubishi', 'Ford', 'Ford', 'Ford']

也就是说,这种方法效率不高,因为您需要为每个元素再次读取整个列表。

改为使用计数器:

from collections import Counter

cars = ['Ford', 'Ford', 'Ford', 'Mitsubishi','Mitsubishi', 'BMW', 'VW']
c = Counter(cars)

cars.sort(key=c.get)

print(cars)
# ['BMW', 'VW', 'Mitsubishi', 'Mitsubishi', 'Ford', 'Ford', 'Ford']