В 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: упс :! Это потому, что метод __cmp__
больше не поддерживается в Python 3. Поэтому я изменил свой старый метод __cmp__
на _cmp
и использовал его для реализации всех 6 из rich comparison methods.
Важное примечание
Я должен отметить, что эта функция сравнения немного странно: это непереходный, другими словами, а> Ь и Ь> с не
обязательно подразумевают > с. А это означает, что результаты его использования в
.sort()
:
непредсказуемый. Кажется, он делает правильные вещи для данных, которые я тестировал, например, он возвращает правильный результат для всех перестановок
[1, 5, 10]
, но я думаю, на самом деле не следует доверять этому для всех входных данных.
альтернативная стратегия, это гарантированно работать это перебор: генерировать все перестановки списка входных & найти перестановку, которая дает максимальный результат. Но, надеюсь, существует более эффективный алгоритм, поскольку генерация всех перестановок большого списка происходит довольно медленно.
Как Antti Haapala указывает в комментариях, мои старые функции сравнения были нестабильны при сравнении различных чисел, которые состоят из одних и тех же последовательностей повторяющихся цифр, например 123123 и 123123123. Такие последовательности должны сравнивать равные, мои старые функции не сделал этого.Последняя модификация затрагивает эту проблему.
Update
Оказывается, что на самом деле mycmp()/_cmp()
является транзитивно. Он также стабилен, теперь он правильно обрабатывает корпус ab == ba
, поэтому его можно использовать с TimSort (или любым другим алгоритмом сортировки). И можно показать, что он дает тот же результат, что и ключевая функция Антти Хаапалы fractionalize()
.
В дальнейшем я буду использовать прописные буквы для представления целых чисел в списке, и я буду использовать строчную версию буквы для представления числа цифр в этом целочисленном значении. Например, a
- это количество цифр в A
. Я буду использовать _
в качестве оператора инфикса для представления конкатенации цифр. Например, A_B
- int(str(A)+str(B)
; обратите внимание, что A_B
имеет a+b
цифр. Арифметически,
A_B = A * 10**b + B
.
Для краткости я буду использовать f()
для представления функции ключа fractionalize()
от Antti Haapala. Обратите внимание, что 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()
в качестве функциональной клавиши достаточно найти перестановку, что доходность максимально возможное целое число , созданное путем конкатенации цифр. Подробности этого аргумента будут слева как упражнение для читателя. :)
Что вы уже пробовали сделать? Как он не работал? –
https://blog.svpino.com/2015/05/07/five-programming-problems-every-software-engineer-should-be-able-to-solve-in-less-than-1-hour?utm_source = facebook & utm_medium = social & utm_content = Oktopost-facebook-profile & utm_campaign = Oktopost-2015-05 + Общие + Кампания –
могут быть отрицательные числа? –