在 Python 2 中,您可以通过传递给 sort 的适当比较函数来做到这一点。
#!/usr/bin/env python
''' Sort a list of non-negative integers so that
if the integers were converted to string, concatenated
and converted back to int, the resulting int is the highest
possible for that list
From http://stackoverflow.com/q/30140796/4014959
Written by PM 2Ring 2015.05.10
Python 2 version
'''
data = [
[50, 2, 1, 9],
[10, 1],
[2, 23, 21],
]
def mycmp(a, b):
a, b = str(a), str(b)
ab, ba = a + b, b + a
if ab == ba:
return 0
if ab < ba:
return -1
return 1
for a in data:
print 'In: ', a
a.sort(cmp=mycmp, reverse=True)
print 'Out:', a
print
输出
In: [50, 2, 1, 9]
Out: [9, 50, 2, 1]
In: [10, 1]
Out: [1, 10]
In: [2, 23, 21]
Out: [23, 2, 21]
在 Python 3 中,sort 不再采用自定义比较函数。 scpio 的回答展示了如何使用functools 将比较函数转换为关键函数,但“手动”做起来并不难。
#!/usr/bin/env python
''' Sort a list of non-negative integers so that
if the integers were converted to string, concatenated
and converted back to int, the resulting int is the highest
possible for that list
From http://stackoverflow.com/q/30140796/4014959
Written by PM 2Ring 2015.05.10
Python 3 compatible version
'''
from __future__ import print_function
class cmpclass(object):
def __init__(self, n):
self.n = str(n)
def __str__(self):
return self.n
def _cmp(self, other):
a, b = self.n, str(other)
ab, ba = a + b, b + a
if ab == ba:
return 0
if ab < ba:
return -1
return 1
def __lt__(self, other): return self._cmp(other) == -1
def __le__(self, other): return self._cmp(other) <= 0
def __eq__(self, other): return self._cmp(other) == 0
def __ne__(self, other): return self._cmp(other) != 0
def __gt__(self, other): return self._cmp(other) == 1
def __ge__(self, other): return self._cmp(other) >= 0
data = [
[50, 2, 1, 9],
[10, 1],
[2, 23, 21],
]
for a in data:
print('In: ', a)
a.sort(key=cmpclass, reverse=True)
print('Out:', a)
print('')
输出
In: [50, 2, 1, 9]
Out: [9, 50, 2, 1]
In: [10, 1]
Out: [1, 10]
In: [2, 23, 21]
Out: [23, 2, 21]
我发布的以前的 Python 3 兼容版本实际上不适用于 Python 3 :oops:!那是因为 Python 3 不再支持 __cmp__ 方法。所以我将旧的 __cmp__ 方法更改为 _cmp 并用它来实现所有 6 个 rich comparison methods。
重要提示
不得不提的是,这个比较函数有点奇怪:它是不可传递的,换句话说,a>b 和 b>c 并不必然隐含 a>c .这意味着在.sort() 中使用它的结果是不可预测的。它似乎确实对我测试过的数据做了正确的事情,例如,它为[1, 5, 10] 的所有排列返回正确的结果,但我想它真的不应该被信任为所有输入这样做。
保证可行的另一种策略是蛮力:生成输入列表的所有排列并找到产生最大结果的排列。但希望有一个更有效的算法,因为生成一个大列表的所有排列是相当慢的。
正如 Antti Haapala 在 cmets 中指出的那样,在比较由相同重复数字序列组成的不同数字时,我的旧比较函数不稳定,例如 123123 和 123123123。这样的序列应该比较相等,我的旧函数没有那。最新的修改解决了这个问题。
更新
事实证明,mycmp() / _cmp() 实际上是可传递的。它也很稳定,现在它可以正确处理ab == ba 的情况,因此可以安全地与 TimSort(或任何其他排序算法)一起使用。并且可以证明它给出了与 Antti Haapala 的fractionalize() 键功能相同的结果。
在下文中,我将使用大写字母来表示列表中的整数,我将使用小写字母来表示该整数中的位数。例如,a 是A 中的位数。我将使用_ 作为中缀运算符来表示数字连接。例如,A_B 是 int(str(A)+str(B);请注意 A_B 有 a+b 数字。算术上,
A_B = A * 10**b + B.
为简洁起见,我将使用f() 来表示Antti Haapala 的fractionalize() 键功能。注意f(A) = A / (10**a - 1)。
现在是一些代数。我会把它放在一个代码块中以保持格式简单。
Let A_B = B_A
A * 10**b + B = B * 10**a + A
A * 10**b - A = B * 10**a - B
A * (10**b - 1) = B * (10**a - 1)
A / (10**a - 1) = B / (10**b - 1)
f(A) = f(B)
So A_B = B_A if & only if f(A) = f(B)
Similarly,
A_B > B_A if & only if f(A) > f(B)
This proves that using mycmp() / _cmp() as the sort comparison function
is equivalent to using fractionalize() as the sort key function.
Note that
f(A_B) = (A * 10**b + B) / (10**(a+b)-1)
and
f(B_A) = (B * 10**a + A) / (10**(a+b)-1)
So f(A_B) = f(B_A) iff A_B = B_A, and f(A_B) > f(B_A) iff A_B > B_A
Let's see what happens with 3 integers.
f(A), f(B), f(C) are just real numbers, so comparing them is
transitive.
And so if f(A) > f(B) and f(B) > f(C) then f(A) > f(C).
This proves that mycmp() / _cmp() is also transitive.
Clearly, if f(A) > f(B) > f(C) then
A_B > B_A, B_C > C_B, A_C > C_A
Let B_C > C_B
For any A,
A * 10**(b+c) + B_C > A * 10**(b+c) + C_B
So A_B_C > A_C_B
i.e. adding the same integer to the beginning of B_C and C_B preserves
the inequality.
Let A_B > B_A
For any C,
(A_B) * 10**c + C > (B_A) * 10**c + C
So A_B_C > B_A_C,
i.e. adding the same integer to the end of A_B and B_A preserves the
inequality.
Using these results, we can show that
if f(A) > f(B) > f(C) then
A_B_C > A_C_B > C_A_B > C_B_A and
A_B_C > B_A_C > B_C_A > C_B_A.
This covers all 6 permutations of [A, B, C] and shows that A_B_C is the
largest possible integer for that list.
一个数学归纳式的论证表明,对任何一个列表进行排序
使用与mycmp() / _cmp() 的成对比较作为有限长度
比较功能或以fractionalize()为关键功能就足够了
找到产生最大可能整数的排列
由数字连接产生。这个论点的细节将是
留给读者作为练习。 :)