使用自定义比较函数对列表的列表进行排序

170 投票
7 回答
258052 浏览
提问于 2025-04-16 13:07

我知道有很多类似的问题,但这些似乎对我没用。

我有一个包含50个子列表的列表,每个子列表有5个元素。我想通过一个自定义的比较函数来对这个列表进行排序。这个函数会计算出每个子列表的“适应度”,然后根据这个适应度来排序。我创建了两个函数,分别叫做比较和适应度:

def compare(item1, item2):
    return (fitness(item1) < fitness(item2))

还有

def fitness(item):
    return item[0]+item[1]+item[2]+item[3]+item[4]

然后我尝试通过以下方式调用它们:

sorted(mylist, cmp=compare)

或者

sorted(mylist, key=fitness)

或者

sorted(mylist, cmp=compare, key=fitness)

或者

sorted(mylist, cmp=lambda x,y: compare(x,y))

我也尝试过使用 list.sort() 方法,参数也是一样。但无论如何,这些函数都没有接收到列表作为参数,而是得到了一个 None。我不知道为什么会这样,作为一个主要使用 C++ 的人,这让我对回调函数的理解产生了困惑。我该如何用自定义函数对这些列表进行排序呢?

编辑 我发现了我的错误。在创建原始列表的过程中,有一个函数没有返回任何东西,但我却使用了它的返回值。抱歉给大家带来了麻烦。

7 个回答

161

另外,你的比较函数不对。它应该返回 -1、0 或 1,而不是你现在用的布尔值(真或假)。正确的比较函数应该是:

def compare(item1, item2):
    if fitness(item1) < fitness(item2):
        return -1
    elif fitness(item1) > fitness(item2):
        return 1
    else:
        return 0

# Calling
list.sort(key=compare)

这个在 Python 2 中可以用。

168

因为提问者想要使用自定义比较函数(这也是我关注这个问题的原因),所以我想在这里给出一个清晰的回答:

通常情况下,你应该使用内置的 sorted() 函数,它可以接收一个自定义的比较器作为参数。我们需要注意的是,在 Python 3 中,参数的名称和含义发生了变化

自定义比较器是如何工作的

当你提供一个自定义比较器时,它通常应该返回一个整数或浮点数,遵循以下规则(这和大多数其他编程语言和框架是一样的):

  • 当左边的项目应该排在右边的项目之前时,返回一个负值(< 0
  • 当左边的项目应该排在右边的项目之后时,返回一个正值(> 0
  • 当左边和右边的项目权重相同,应该“平等”排序时,返回 0

在提问者的具体问题中,可以使用以下自定义比较函数:

def compare(item1, item2):
    return fitness(item1) - fitness(item2)

使用减法操作是个聪明的技巧,因为当左边的 item1 的权重大于右边的 item2 时,它会返回正值。因此 item1 会被排在 item2 之后。

如果你想反转排序顺序,只需反转减法: return fitness(item2) - fitness(item1)

在 Python 2 中调用 sorted()

sorted(mylist, cmp=compare)

或者:

sorted(mylist, cmp=lambda item1, item2: fitness(item1) - fitness(item2))

在 Python 3 中调用 sorted()

from functools import cmp_to_key
sorted(mylist, key=cmp_to_key(compare))

或者:

from functools import cmp_to_key
sorted(mylist, key=cmp_to_key(lambda item1, item2: fitness(item1) - fitness(item2)))
31
>>> l = [list(range(i, i+4)) for i in range(10,1,-1)]
>>> l
[[10, 11, 12, 13], [9, 10, 11, 12], [8, 9, 10, 11], [7, 8, 9, 10], [6, 7, 8, 9], [5, 6, 7, 8], [4, 5, 6, 7], [3, 4, 5, 6], [2, 3, 4, 5]]
>>> sorted(l, key=sum)
[[2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8], [6, 7, 8, 9], [7, 8, 9, 10], [8, 9, 10, 11], [9, 10, 11, 12], [10, 11, 12, 13]]

上面的代码可以正常运行。你是不是做了什么不同的事情呢?

注意,你的关键函数其实就是 sum;不需要特别写出来。

撰写回答