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

DaC*_*own 53 python sorting list callback

我知道有几个问题就像这样,但我似乎无法得到他们的工作答案.

我有一个列表列表,50次5个元素.现在我想通过对每个元素应用自定义比较函数来对此列表进行排序.此函数计算列表的适合度,元素应按顺序排序.我创建了两个函数,比较和健身:

def compare(item1, item2):
    return (fitness(item1) < fitness(item2))
Run Code Online (Sandbox Code Playgroud)

def fitness(item):
    return item[0]+item[1]+item[2]+item[3]+item[4]
Run Code Online (Sandbox Code Playgroud)

然后我试着通过以下方式打电话给他

sorted(mylist, cmp=compare)
Run Code Online (Sandbox Code Playgroud)

要么

sorted(mylist, key=fitness)
Run Code Online (Sandbox Code Playgroud)

要么

sorted(mylist, cmp=compare, key=fitness)
Run Code Online (Sandbox Code Playgroud)

要么

sorted(mylist, cmp=lambda x,y: compare(x,y))
Run Code Online (Sandbox Code Playgroud)

我也尝试使用相同的参数list.sort().但无论如何,函数不会将列表作为参数而是一个参数None.我不知道为什么会这样,主要来自C++,这与我的回调函数的任何想法相矛盾.如何使用自定义函数对此列表进行排序?

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

小智 65

此外,您的比较功能不正确.它需要返回-1,0或1,而不是布尔值.正确的比较函数是:

def compare(item1, item2):
    if fitness(item1) < fitness(item2):
        return -1
    elif fitness(item1) > fitness(item2):
        return 1
    else:
        return 0
Run Code Online (Sandbox Code Playgroud)

  • 或者只是,`返回健身(item1) - 健身(第2项)`.比较函数不必返回-1或1,而只是返回负数或正数(或零).参考:http://docs.python.org/2/library/stdtypes.html#mutable-sequence-types (28认同)
  • 对于 py3,使用`key=functools.cmp_to_key(compare)`。请参阅 JustAC0der 的回答 (21认同)
  • `sorted(myList,key = lambda x:-fitness(x))` (7认同)
  • 或`sorted(myList,key = fitness,reverse = True)` (6认同)

Kat*_*iel 28

>>> 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]]
Run Code Online (Sandbox Code Playgroud)

以上工作.你在做一些不同的事吗?

请注意,您的关键功能只是sum; 没有必要明确地写它.

  • 不回答问题。该问题要求使用自定义比较器,但未显示。 (3认同)

Jus*_*der 13

您需要稍微修改您的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))
Run Code Online (Sandbox Code Playgroud)

输出:

[[2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8], [5, 6, 7, 8, 9]]
Run Code Online (Sandbox Code Playgroud)

工作:)


Lar*_*erg 5

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

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

自定义比较器的工作方式

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

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

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

def compare(item1, item2):
    return fitness(item1) - fitness(item2)
Run Code Online (Sandbox Code Playgroud)

使用减号运算是一个不错的技巧,因为当左一项的权重(此处item1:)大于右一项的权重(此处:)时,它会产生正值item2。因此,item1将在item2之后排序。

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

在Python 2中调用sorted()

sorted(mylist, key=cmp(compare))
Run Code Online (Sandbox Code Playgroud)

要么:

sorted(mylist, cmp=lambda item1, item2: fitness(item1) - fitness(item2))
Run Code Online (Sandbox Code Playgroud)

在Python 3中调用sorted()

from functools import cmp_to_key
sorted(mylist, key=cmp_to_key(compare))
Run Code Online (Sandbox Code Playgroud)

要么:

from functools import cmp_to_key
sorted(mylist, key=cmp_to_key(lambda item1, item2: fitness(item1) - fitness(item2)))
Run Code Online (Sandbox Code Playgroud)

  • 这是最完整的、应该被接受的答案。 (4认同)
  • 祝福你能弄清楚这一点。对于外行来说,关于 Py3 语法的一切都是不直观的;函数的名称(过去分词而不是动词)、参数名称(key 对读者没有任何帮助),以及神奇的咒语 cmp_to_key。 (3认同)

Rex*_*ker 5

一种简单的查看方式是Python 中的sorted()(or list.sort()) 函数一次对一个键进行操作。它通过列表元素的单次传递构建一个键列表。然后,它确定哪个键更大或更小,并将它们按正确的顺序排列。

因此,正如我发现的,解决方案是制作一个给出正确顺序的密钥。在这里,Python 可以将键用作strtuple。这不需要functools像其他示例中那样的模块:

# task: sort the list of strings, such that items listed as '_fw' come before '_bw'
foolist = ['Goo_fw', 'Goo_bw', 'Foo_fw', 'Foo_bw', 'Boo_fw', 'Boo_bw']

def sortfoo(s):
    s1, s2 = s.split('_')
    r = 1 if s2 == 'fw' else 2     # forces 'fw' to come before 'bw'
    return (r, s1)                 # order first by 'fw'/'bw', then by name

foolist.sort(key=sortfoo)          # sorts foolist inplace

print(foolist)
# prints:
# ['Boo_fw', 'Foo_fw', 'Goo_fw', 'Boo_bw', 'Foo_bw', 'Goo_bw']
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为元组是用于排序的合法键。这可以根据您的需要进行定制,其中不同的排序元素按照排序的重要性顺序简单地堆叠到这个元组中。


Zeu*_*eus 5

对于 python3x

arr = [1, 33, 23, 56, 9]

def compare_func(x, y):
     return x - y
Run Code Online (Sandbox Code Playgroud)

1.使用带有比较功能的arr.sort

arr.sort(key=cmp_to_key(compare_func))
Run Code Online (Sandbox Code Playgroud)

2.sorted用于获取新列表

new_list = sorted(arr, key=cmp_to_key(lambda x, y: x - y)))
Run Code Online (Sandbox Code Playgroud)

3.将arr.sort与lambda一起使用

arr.sort(key=cmp_to_key(lambda x, y: x - y))
Run Code Online (Sandbox Code Playgroud)