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)