使用自定义比较功能对列表列表进行排序


75

我知道有几个这样的问题,但是它们似乎对我没有用。

我有一个列表,5元素乘以50。我想通过对每个元素应用自定义比较功能来对列表进行排序。此函数计算要对元素进行排序的列表的适用性。我创建了两个函数,比较和适应性:

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 ++,这与我对回调函数的任何想法相矛盾。如何使用自定义功能对列表进行排序?

编辑 我发现了我的错误。在创建原始列表的链中,一个函数未返回任何内容,但使用了返回值。抱歉打扰了


2
显示代码,您期望得到什么。

3
请注意,您的compare函数是不正确的,因为它仅返回True或False,并且不会区分item1item2等于和item1大于item2。正确的书写方式compare将是return cmp(fitness(item1), fitness(item2))。但是使用key更好。
jchl 2011年

1
cmp关键字已在Python 3中删除。您现在可以key=functools.cmp_to_key(<function>)在导入后使用functools
user136036 '02

Answers:


30
>>> 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;无需明确地编写它。


1
您绝对正确,其他一些代码导致了错误,谢谢。再次感谢您,至少现在我有一个使用函数而不是lambda表达式作为键值的示例。以前寻找解决方案时找不到我。
DaClown 2011年

31
不回答问题。该问题要求使用自定义比较器,但未显示。
aaa90210 '18

81

另外,您的比较功能不正确。它需要返回-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)

38
或者只是return fitness(item1) - fitness(item2)。比较函数不必返回-1或1,而只需返回一个负数或正数(或零)。参考:docs.python.org/2/library/stdtypes.html#mutable-sequence-types
LarsH 2013年

7
sorted(myList, key=lambda x: -fitness(x))
19 Lee,

6
sorted(myList, key=fitness, reverse=True)
橙色

7
对于py3,请使用key=functools.cmp_to_key(compare)。参见JustAC0der的回答
Donn Lee

32

由于OP要求使用自定义比较功能(这也是导致我提出这个问题的原因),因此我想在这里给出可靠的答案:

通常,您要使用内置的 sorted()以自定义比较器为其参数函数。我们需要注意以下事实:在Python 3中,参数名称和语义已更改。

自定义比较器的工作方式

提供自定义比较器时,通常应返回遵循以下模式的整数/浮点值(与大多数其他编程语言和框架一样):

  • < 0当左项目应排右项目之前时,返回负值()
  • > 0当左侧项目应排右侧项目之后时,返回正值()
  • 返回0时,左边和右边的项目有相同的权重,应该没有先例“同样”命令

在OP的特定情况下,可以使用以下自定义比较功能:

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)))

请注意,cmp_to_keycompare()功能可将Python 2样式函数更改为Python 3所需的样式
。– DocOc

它不仅可以代替Python 2样式,cmp_to_key还可以提供一个比较器,该比较器可以直接比较两个元素,这对于那些您不能或不想直接将列表元素映射到值的情况非常方便。
拉尔斯·布伦伯格

2
这是最完整的,应该接受的答案。
MattSom

31

您需要略微修改compare函数并将functools.cmp_to_key其传递给sorted。示例代码:

import functools

lst = [list(range(i, i+5)) for i in range(5, 1, -1)]

def fitness(item):
    return item[0]+item[1]+item[2]+item[3]+item[4]
def compare(item1, item2):
    return fitness(item1) - fitness(item2)

sorted(lst, key=functools.cmp_to_key(compare))

输出:

[[2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8], [5, 6, 7, 8, 9]]

作品:)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.