Python 对列表进行排序以形成可能的最大数字
我试图写一个函数,给定一个非负整数列表,将它们排列成可能的最大数 例如,给定Python 对列表进行排序以形成可能的最大数字,python,python-2.7,Python,Python 2.7,我试图写一个函数,给定一个非负整数列表,将它们排列成可能的最大数 例如,给定[50,2,1,9],形成的最大数字是95021 以下是我试图解决此问题的代码: a = [50, 2, 1, 9] a.sort() ans = [] for i in range(len(a)-1,-1,-1): ans.append(a[i]) print ''.join(map(str,ans)) 然而,我得到了50921,因为50是最大的,但它应该首先显示9。在Python 2中,您可以通过传递给排
[50,2,1,9]
,形成的最大数字是95021
以下是我试图解决此问题的代码:
a = [50, 2, 1, 9]
a.sort()
ans = []
for i in range(len(a)-1,-1,-1):
ans.append(a[i])
print ''.join(map(str,ans))
然而,我得到了
50921
,因为50
是最大的,但它应该首先显示9
。在Python 2中,您可以通过传递给排序的适当比较函数来完成这一操作
import functools
def cmpr(x, y):
xy = str(x) + str(y)
yx = str(y) + str(x)
return -1 if (xy > yx) else 1
a = [50, 2, 1, 9]
a.sort(key=functools.cmp_to_key(cmpr))
#!/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
在Python3中,sort
不再采用自定义比较函数。scpio的回答说明了如何使用functools
将比较函数转换为键函数,但“手工”并不难
我之前发布的Python 3兼容版本实际上不适用于Python 3:oops:!这是因为Python3不再支持\uu\cmp\uu
方法。因此,我将旧的\uuump\uump
方法更改为\ucmp
,并使用它来实现所有6种方法
重要提示
我必须提到这个比较函数有点奇怪:它是不可传递的,换句话说,a>b和b>c并不一定意味着a>c。这意味着在.sort()
中使用它的结果是不可预测的。它似乎对我测试过的数据做了正确的事情,例如,它为[1,5,10]
的所有排列返回了正确的结果,但我想它确实不应该对所有输入都这样做
另一种保证有效的策略是蛮力:生成输入列表的所有排列并找到产生最大结果的排列。但希望有一个更有效的算法,因为生成一个大列表的所有排列相当慢
正如Antti Haapala在评论中指出的那样,我以前的比较函数在比较由相同重复数字序列组成的不同数字时是不稳定的,例如123123和123123。这样的序列应该是相等的,我以前的函数没有这样做。最新的修改解决了这个问题
更新
事实证明,mycmp()/\u cmp()
实际上是可传递的。它也很稳定,因为它正确地处理了ab==ba
的情况,所以它可以安全地与TimSort(或任何其他排序算法)一起使用。它可以显示出与Antti Haapala的分馏()
键函数相同的结果
在下面的内容中,我将使用大写字母表示列表中的整数,并使用小写字母表示该整数中的位数。例如,a
是a
中的位数。我将使用作为中缀运算符来表示数字连接。例如,A\u B
是int(str(A)+str(B)
;注意A\u B
有A+B
位。算术上,
A_B=A*10**B+B
为了简洁起见,我将使用f()
来表示Antti Haapala的分馏()
键函数
现在学习一些代数。我将把它放在一个代码块中,以保持格式简单
让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)
所以A_B=B_A当且仅当f(A)=f(B)
同样地,
A_B>B_A当且仅当f(A)>f(B)
这证明使用mycmp()/_cmp()作为排序比较函数
相当于使用分馏()作为排序键函数。
注意
f(A_B)=(A*10**B+B)/(10**(A+B)-1)
和
f(B_A)=(B*10**A+A)/(10**(A+B)-1)
所以当A_B=B_A时f(A_B)=f(B_A),当A_B>B_A时f(A_B)>f(B_A)
让我们看看3个整数会发生什么。
f(A),f(B),f(C)都是实数,所以比较它们是非常困难的
及物的
如果f(A)>f(B)和f(B)>f(C),那么f(A)>f(C)。
这证明mycmp()/_cmp()也是可传递的。
显然,如果f(A)>f(B)>f(C),那么
A_B>B_A,B_C>C_B,A_C>C_A
让B_C>C_B
对于任何一个,
A*10**(b+c)+b\U c>A*10**(b+c)+c\b
所以A_B_C>A_C_B
i、 e.将相同的整数添加到B_C和C_B的开头将保留
不平等。
让A_B>B_A
对于任何C,
(A_B)*10**c+c>(B_A)*10**c+c
所以A_B_C>B_A_C,
i、 e.将相同的整数添加到A_B和B_A的末尾将保留
不平等。
利用这些结果,我们可以证明
如果f(A)>f(B)>f(C),那么
A_B_C>A_C_B>C_A_B>C_B_A和
A_B_C>B_A_C>B_C_A>C_B_A。
这涵盖了[A,B,C]的所有6种排列,并表明A_B_C是
该列表的最大可能整数。
数学归纳式参数表明,对任何
使用成对比较的有限长度,将mycmp()
/\u cmp()
作为
比较函数或使用分馏()
作为键函数即可
找到产生最大可能整数的置换
由数字连接生成。此参数的详细信息将
留给读者一个练习。这里有一个丑陋的解决方案,它不需要将cmp
比较函数传递给排序的。基本上,键函数取每个数字并计算一个有理数,该有理数以该数字为基础;就是
排序键0将0排序为最小值,1后跟大多数零将使键最接近0.1
,因此排序为第二小值。由数字9组成的数字的排序键都等于1
;在99
之前或之后对9
进行排序实际上并不重要
使用这些值作为键进行排序必然会得到正确的输出,除非使用的数字对于浮点精度来说太大。(可能比2**53
快得多)
这样我们就得到了fo
In: [50, 2, 1, 9]
Out: [9, 50, 2, 1]
In: [10, 1]
Out: [1, 10]
In: [2, 23, 21]
Out: [23, 2, 21]
#!/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]
0 => 0
100 => 100/999 == 0.100100100...
10 => 10/99 == 0.1010101010...
1 => 1/9 == 0.1111111111...
11 => 11/99 == 0.1111111111...
12 => 12/99 == 0.1212121212...
9 => 9/9 == 1
99 => 99/99 == 1
999 => 999/999 == 1
# for Python 2, not needed in Python 3
from __future__ import division
a = [50, 5, 51, 59, 2, 1, 9, 98]
def fractionalize(i):
divisor = 9
while divisor < i:
divisor = 10 * divisor + 9
return i / divisor
print(sorted(a, key=fractionalize, reverse=True))
[9, 98, 59, 5, 51, 50, 2, 1]
from math import ceil, log10
print(sorted(a, key=lambda i: i and i/(10**ceil(log10(i+1))-1), reverse=True))
from fractions import Fraction
sorted(a, key=lambda n: Fraction(n, 10**len(str(n))-1), reverse=True)
[9, 98, 59, 5, 51, 50, 2, 1]
import itertools
digits = ['50', '2', '1', '9']
perms = itertools.permutations(digits)
sorted_numlist = sorted(perms)
print sorted_numlist[-1]
import itertools
digits = ['11', '68', '4', '12']
perms = itertools.permutations(digits)
numlist = []
for sublist in perms:
permutated_num = "".join(sublist)
numlist.append(int(permutated_num))
sorted_numlist = sorted(numlist)
print sorted_numlist[-1]
>>> from itertools import permutations, imap
>>> a = [50, 2, 1, 9]
>>> int(max(imap(''.join, permutations(map(str, a)))))
95021
from itertools import permutations as pm
def max_number(lst):
if all(v == 0 for v in nums):
return "0"
lst1 = [str(item) for item in lst]
return max([int(''.join(list(perm))) for perm in pm(lst, len(lst1))])
def create_largest_number(number_list):
res=''
for i in number_list:
res= res+ str(i)
new=''.join(sorted(res))
return new[::-1]
number_list=[23,45,67]
largest_number=create_largest_number(number_list)
print(largest_number)