如果compare函数需要比较项的值,如何使用Python3排序键?

时间:2017-06-21 21:38:05

标签: python python-3.x sorting

下面是一个示例,其中我使用了比较器函数,该函数明确要求两个项目(x+y < y+x)提供比较。问题是如何在不使用cmp_to_key函数的情况下编写以下内容,因为key只需要一个输入。

以下程序是解决问题的方法:

给定一个非负整数列表,排列它们,使它们形成最大数字。

例如,给定[3, 30, 34, 5, 9],最大的数字是9534330

from functors import cmp_to_key

def largestNumber(self, nums):
    numStr = [str(i) for i in nums]

    def str_cmp(x, y):
        if y+x < x+y: return -1
        elif y+x > x+y: return 1
        else: return 0

    numStr.sort(key=cmp_to_key(str_cmp))

    return "".join(numStr).lstrip('0') or '0'

2 个答案:

答案 0 :(得分:1)

您可以编写一个自定义类,以您需要的方式实现__lt__(实现<比较的方法):

class Comp(object):
    def __init__(self, value):
        self.value = str(value)

    def __lt__(self, other):
        return other.value + self.value <= self.value + other.value

这应该产生相同的&#34;排序&#34;:

>>> sorted([3, 30, 34, 5, 9], key=Comp)
[9, 5, 34, 3, 30]

但我不确定这是否确实提供了"total ordering"(可能,我只是有些疑惑)如果它确实没有提供意想不到的结果(在任何Python中)版本独立于keycmp参数。)

答案 1 :(得分:1)

只是换另一种方式:

from itertools import cycle, islice

def extender(n):
    def extend(x):
        s = str(x)
        return "".join(islice(cycle(s), n))
    return extend

def biggest_number(input):
    if (len(input) == 0):
        return 0
    extend = extender(len(str(max(input))) * 2)
    s = sorted(input, key=extend, reverse=True)
    return int("".join(map(str, s)))

基本上,您可以根据需要重复获取数组中的每个元素并使它们具有相同的长度。然后你做一个词典排序。 (此时数字排序将是相同的,但我们在完成时需要字符串。)

,对于[3, 30, 34, 5, 9],我们发现最长的数字是2位数,因此我们通过根据需要重复数字将所有内容扩展为三位数。这些是使用的关键:

[333, 303, 343, 555, 999]

然后我们对结果进行排序,降序和组合:

[9, 5, 34, 3, 30]
9534330

直觉来自于&#34;选择具有最大前导数字的数字。&#34;问题出现在我们应该如何处理平局。例如,我们为什么要在30之前选择3?答案是,在3之后可能出现的最大数字是另一个3.(如果有更大的数字可用,我们已经选择它了。)所以将3视为&#34; 333333 ...&# 34;帮助我们选择正确的。类似的问题:我们为什么选择10而不是100?这使我们意识到10之后的最佳结果是以10开头的另一个数字。(我们已经选择了11个或更多)。所以把它想象成&#34; 10101010 ...&#34;和&#34; 100100100100 ...&#34;。事实证明,你只需要扩展到 n * 2 位,其中 n 是最长数字的长度。

我意识到这有点令人困惑。我写了一个测试来确保这一切都是正确的。 (它与原始代码进行比较。)

from functools import cmp_to_key
import random

def largestNumber(nums):
    numStr = [str(i) for i in nums]

    def str_cmp(x, y):
        if y+x < x+y: return -1
        elif y+x > x+y: return 1
        else: return 0

    numStr.sort(key=cmp_to_key(str_cmp))

    return "".join(numStr).lstrip('0') or '0'

for i in range(1000000):
    input = [random.randint(0, 1000) for _ in range(random.randint(0, 100))]
    if biggest_number(input) != int(largestNumber(input)):
        print("FAILED: {}".format(input))
    if i % 100 == 0:
        print(i)

我还没有找到不起作用的输入。我相信这段代码是正确的。

所有这些都说,我不知道你为什么不想使用cmp_to_key。 : - )