Python 3.x에서 2.x와 유사한 정렬 동작을 얻으려면 어떻게해야합니까?
3.x에서 Python 2.x의 정렬 동작을 복제 (가능한 경우 개선)하여 int
, float
등과 같은 상호 정렬 가능한 유형 이 예상대로 정렬되고 상호 정렬 불가능한 유형이 출력 내에서 그룹화되도록 노력하고 있습니다.
다음은 제가 말하는 내용의 예입니다.
>>> sorted([0, 'one', 2.3, 'four', -5]) # Python 2.x
[-5, 0, 2.3, 'four', 'one']
>>> sorted([0, 'one', 2.3, 'four', -5]) # Python 3.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: str() < int()
키 매개 변수에 대한 클래스를 사용하는 이전 시도 sorted()
( 이종 시퀀스 정렬을 위해이 키 클래스가 이상하게 작동하는 이유 참조 )는 근본적으로 깨졌습니다.
- 값을 비교하려고 시도하고
- 실패하면 해당 유형의 문자열 표현을 비교하는 것으로 되돌아갑니다.
BrenBarn의 우수한 답변에서 설명했듯이 자동 정렬로 이어질 수 있습니다 .
코딩을 시도하지 않고 처음에 거부했던 순진한 접근 방식은 (type, value)
튜플 을 반환하는 키 함수를 사용하는 것입니다 .
def motley(value):
return repr(type(value)), value
그러나 이것은 내가 원하는 것을하지 않습니다. 우선 상호 정렬 가능한 유형의 자연스러운 순서를 깨뜨립니다.
>>> sorted([0, 123.4, 5, -6, 7.89])
[-6, 0, 5, 7.89, 123.4]
>>> sorted([0, 123.4, 5, -6, 7.89], key=motley)
[7.89, 123.4, -6, 0, 5]
둘째, 입력에 본질적으로 정렬 할 수없는 동일한 유형의 두 개체가 포함 된 경우 예외가 발생합니다.
>>> sorted([{1:2}, {3:4}], key=motley)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: dict() < dict()
... 이는 Python 2.x와 3.x 모두에서 표준 동작입니다.하지만 이상적으로는 이러한 유형을 함께 그룹화하고 싶습니다 (순서는 특별히 신경 쓰지 않지만 원래 순서를 유지한다는 Python의 안정적인 정렬 보장).
특수 케이스를 사용하여 숫자 유형에 대한 첫 번째 문제를 해결할 수 있습니다.
from numbers import Real
from decimal import Decimal
def motley(value):
numeric = Real, Decimal
if isinstance(value, numeric):
typeinfo = numeric
else:
typeinfo = type(value)
return repr(typeinfo), value
... 그것이 가능한 한 작동합니다.
>>> sorted([0, 'one', 2.3, 'four', -5], key=motley)
[-5, 0, 2.3, 'four', 'one']
...하지만 상호 순서가 가능한 다른 고유 한 (사용자 정의 된) 유형이있을 수 있다는 사실을 설명하지 않으며, 물론 본질적으로 순서가 불가능한 유형에서는 여전히 실패합니다.
>>> sorted([{1:2}, {3:4}], key=motley)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: dict() < dict()
임의적이고 구별되지만 상호 순서가 가능한 유형의 문제 와 본질적으로 순서가 불가능한 유형 의 문제 를 모두 해결하는 또 다른 접근 방식이 있습니까?
어리석은 생각 : 서로 비교할 수있는 그룹의 모든 다른 항목을 나누고 개별 그룹을 정렬 한 다음 마지막으로 연결하는 첫 번째 패스를 만드십시오. 항목이 그룹의 첫 번째 구성원과 비교할 수 있다면 그룹의 모든 구성원과 비교할 수 있다고 가정합니다. 다음과 같은 것 (Python3) :
import itertools
def python2sort(x):
it = iter(x)
groups = [[next(it)]]
for item in it:
for group in groups:
try:
item < group[0] # exception if not comparable
group.append(item)
break
except TypeError:
continue
else: # did not break, make new group
groups.append([item])
print(groups) # for debugging
return itertools.chain.from_iterable(sorted(group) for group in groups)
비교할 수있는 항목이없는 한심한 경우에는 2 차 실행 시간이 있지만 확실히 알 수있는 유일한 방법은 가능한 모든 조합을 확인하는 것입니다. 복소수와 같이 정렬 할 수없는 항목의 긴 목록을 정렬하려는 모든 사람에게 합당한 처벌로 2 차 동작을 참조하십시오. 일부 문자열과 정수가 혼합 된보다 일반적인 경우 속도는 일반 정렬의 속도와 유사해야합니다. 빠른 테스트 :
In [19]: x = [0, 'one', 2.3, 'four', -5, 1j, 2j, -5.5, 13 , 15.3, 'aa', 'zz']
In [20]: list(python2sort(x))
[[0, 2.3, -5, -5.5, 13, 15.3], ['one', 'four', 'aa', 'zz'], [1j], [2j]]
Out[20]: [-5.5, -5, 0, 2.3, 13, 15.3, 'aa', 'four', 'one', 'zz', 1j, 2j]
또한 비교할 수없는 항목이 만나는 순서대로 그룹이 형성되기 때문에 '안정된 정렬'인 것 같습니다.
이 답변은 Python 3에서 모든 세부 사항에서 Python 2 정렬 순서를 충실히 재현하는 것을 목표로합니다.
실제 파이썬이 구현은 상당히 관련되어 있지만, object.c
의는default_3way_compare
인스턴스가 정상 비교 규칙을 구현할 수있는 기회를 제공 한 후 최종 대체 않습니다. 이것은 개별 유형에 비교할 기회가 주어진 후입니다 ( __cmp__
또는 __lt__
후크 를 통해 ).
이 함수를 래퍼에서 순수 Python으로 구현하고 규칙 ( dict
및 특히 복소수)에 대한 예외를 에뮬레이션하면 Python 3에서 동일한 Python 2 정렬 의미를 얻을 수 있습니다.
from numbers import Number
# decorator for type to function mapping special cases
def per_type_cmp(type_):
try:
mapping = per_type_cmp.mapping
except AttributeError:
mapping = per_type_cmp.mapping = {}
def decorator(cmpfunc):
mapping[type_] = cmpfunc
return cmpfunc
return decorator
class python2_sort_key(object):
_unhandled_types = {complex}
def __init__(self, ob):
self._ob = ob
def __lt__(self, other):
_unhandled_types = self._unhandled_types
self, other = self._ob, other._ob # we don't care about the wrapper
# default_3way_compare is used only if direct comparison failed
try:
return self < other
except TypeError:
pass
# hooks to implement special casing for types, dict in Py2 has
# a dedicated __cmp__ method that is gone in Py3 for example.
for type_, special_cmp in per_type_cmp.mapping.items():
if isinstance(self, type_) and isinstance(other, type_):
return special_cmp(self, other)
# explicitly raise again for types that won't sort in Python 2 either
if type(self) in _unhandled_types:
raise TypeError('no ordering relation is defined for {}'.format(
type(self).__name__))
if type(other) in _unhandled_types:
raise TypeError('no ordering relation is defined for {}'.format(
type(other).__name__))
# default_3way_compare from Python 2 as Python code
# same type but no ordering defined, go by id
if type(self) is type(other):
return id(self) < id(other)
# None always comes first
if self is None:
return True
if other is None:
return False
# Sort by typename, but numbers are sorted before other types
self_tname = '' if isinstance(self, Number) else type(self).__name__
other_tname = '' if isinstance(other, Number) else type(other).__name__
if self_tname != other_tname:
return self_tname < other_tname
# same typename, or both numbers, but different type objects, order
# by the id of the type object
return id(type(self)) < id(type(other))
@per_type_cmp(dict)
def dict_cmp(a, b, _s=object()):
if len(a) != len(b):
return len(a) < len(b)
adiff = min((k for k in a if a[k] != b.get(k, _s)), key=python2_sort_key, default=_s)
if adiff is _s:
# All keys in a have a matching value in b, so the dicts are equal
return False
bdiff = min((k for k in b if b[k] != a.get(k, _s)), key=python2_sort_key)
if adiff != bdiff:
return python2_sort_key(adiff) < python2_sort_key(bdiff)
return python2_sort_key(a[adiff]) < python2_sort_key(b[bdiff])
후크 를 통해 유형 자체에서 지원되기 때문에 Python 2에서 구현 된 사전 정렬 처리를 통합했습니다 __cmp__
. 나는 자연스럽게 키와 값에 대한 Python 2 주문을 고수했습니다.
또한 다음과 같이 정렬하려고 할 때 Python 2에서 예외가 발생하므로 복소수에 대한 특수 대 / 소문자를 추가했습니다.
>>> sorted([0.0, 1, (1+0j), False, (2+3j)])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: no ordering relation is defined for complex numbers
Python 2 동작을 정확하게 에뮬레이트하려면 더 많은 특수 사례를 추가해야 할 수 있습니다.
어쨌든 복소수를 정렬하려면 숫자 가 아닌 그룹에 일관되게 배치해야합니다. 예 :
# Sort by typename, but numbers are sorted before other types
if isinstance(self, Number) and not isinstance(self, complex):
self_tname = ''
else:
self_tname = type(self).__name__
if isinstance(other, Number) and not isinstance(other, complex):
other_tname = ''
else:
other_tname = type(other).__name__
일부 테스트 사례 :
>>> sorted([0, 'one', 2.3, 'four', -5], key=python2_sort_key)
[-5, 0, 2.3, 'four', 'one']
>>> sorted([0, 123.4, 5, -6, 7.89], key=python2_sort_key)
[-6, 0, 5, 7.89, 123.4]
>>> sorted([{1:2}, {3:4}], key=python2_sort_key)
[{1: 2}, {3: 4}]
>>> sorted([{1:2}, None, {3:4}], key=python2_sort_key)
[None, {1: 2}, {3: 4}]
여기서 Python 3을 실행하지 않지만 아마도 이와 같은 것이 작동 할 것입니다. "값"에 대해 "보다 작음"비교를 수행하면 예외가 발생하는지 확인한 다음 문자열로 변환하는 것과 같이 해당 사례를 처리하기 위해 "무언가"를 수행하는지 테스트합니다.
물론 동일한 유형은 아니지만 상호 순서가 가능한 다른 유형이 목록에있는 경우 더 특별한 처리가 필요합니다.
from numbers import Real
from decimal import Decimal
def motley(value):
numeric = Real, Decimal
if isinstance(value, numeric):
typeinfo = numeric
else:
typeinfo = type(value)
try:
x = value < value
except TypeError:
value = repr(value)
return repr(typeinfo), value
>>> print sorted([0, 'one', 2.3, 'four', -5, (2+3j), (1-3j)], key=motley)
[-5, 0, 2.3, (1-3j), (2+3j), 'four', 'one']
예외의 사용을 피하고 유형 기반 솔루션을 사용하기 위해 다음과 같이 생각해 냈습니다.
#! /usr/bin/python3
import itertools
def p2Sort(x):
notImpl = type(0j.__gt__(0j))
it = iter(x)
first = next(it)
groups = [[first]]
types = {type(first):0}
for item in it:
item_type = type(item)
if item_type in types.keys():
groups[types[item_type]].append(item)
else:
types[item_type] = len(types)
groups.append([item])
#debuggng
for group in groups:
print(group)
for it in group:
print(type(it),)
#
for i in range(len(groups)):
if type(groups[i][0].__gt__(groups[i][0])) == notImpl:
continue
groups[i] = sorted(groups[i])
return itertools.chain.from_iterable(group for group in groups)
x = [0j, 'one', 2.3, 'four', -5, 3j, 0j, -5.5, 13 , 15.3, 'aa', 'zz']
print(list(p2Sort(x)))
목록에 다른 유형을 보유하기위한 추가 사전과 유형 보유 변수 (notImpl)가 필요합니다. 또한 여기에서는 float와 int가 혼합되지 않습니다.
산출:
================================================================================
05.04.2017 18:27:57
~/Desktop/sorter.py
--------------------------------------------------------------------------------
[0j, 3j, 0j]
<class 'complex'>
<class 'complex'>
<class 'complex'>
['one', 'four', 'aa', 'zz']
<class 'str'>
<class 'str'>
<class 'str'>
<class 'str'>
[2.3, -5.5, 15.3]
<class 'float'>
<class 'float'>
<class 'float'>
[-5, 13]
<class 'int'>
<class 'int'>
[0j, 3j, 0j, 'aa', 'four', 'one', 'zz', -5.5, 2.3, 15.3, -5, 13]
Python 3.2+의 한 가지 방법은 functools.cmp_to_key()
. 이를 통해 값을 비교 한 다음 유형의 문자열 표현을 비교하는 솔루션을 신속하게 구현할 수 있습니다. 순서가 지정되지 않은 유형을 비교할 때 발생하는 오류를 피하고 원래 경우와 같이 순서를 유지할 수도 있습니다.
from functools import cmp_to_key
def cmp(a,b):
try:
return (a > b) - (a < b)
except TypeError:
s1, s2 = type(a).__name__, type(b).__name__
return (s1 > s2) - (s1 < s2)
예 ( Martijn Pieters의 답변 에서 가져온 입력 목록 ) :
sorted([0, 'one', 2.3, 'four', -5], key=cmp_to_key(cmp))
# [-5, 0, 2.3, 'four', 'one']
sorted([0, 123.4, 5, -6, 7.89], key=cmp_to_key(cmp))
# [-6, 0, 5, 7.89, 123.4]
sorted([{1:2}, {3:4}], key=cmp_to_key(cmp))
# [{1: 2}, {3: 4}]
sorted([{1:2}, None, {3:4}], key=cmp_to_key(cmp))
# [None, {1: 2}, {3: 4}]
이는 항상 3 원 비교가 수행되어 시간 복잡성이 증가한다는 단점이 있습니다. 그러나 솔루션은 오버 헤드가 적고 짧고 깨끗하며 cmp_to_key()
이런 종류의 Python 2 에뮬레이션 사용 사례를 위해 개발 되었다고 생각 합니다.
이 문제는 다음과 같은 방법으로 해결할 수 있습니다.
- 유형별로 그룹화합니다.
- 각 유형의 단일 대표를 비교하여 비교할 수있는 유형을 찾으십시오.
- 유사한 유형의 그룹을 병합합니다.
- 가능한 경우 병합 된 그룹을 정렬합니다.
- (정렬 된) 병합 된 그룹의 수익
를 사용하여 유형에서 결정적이고 정렬 가능한 키 함수를 얻을 수 있습니다 repr(type(x))
. 여기서 '유형 계층'은 유형 자체의 재현에 의해 결정됩니다. 이 방법의 결함은 두 유형이 동일한 경우 __repr__
(인스턴스가 아닌 유형 자체) 유형을 '혼동'하게된다는 것입니다. 이것은 tuple을 반환하는 키 함수를 사용하여 해결할 수 (repr(type), id(type))
있지만이 솔루션에서는 구현하지 않았습니다.
Bas Swinkel에 비해 내 방법의 장점은 정렬 할 수없는 요소 그룹을 더 깔끔하게 처리한다는 것입니다. 우리는 2 차 행동이 없습니다. 대신, 함수는 sorted ()) 동안 첫 번째 순서를 시도한 후에 포기합니다.
내 방법은 iterable에 매우 많은 수의 다른 유형이있는 시나리오에서 최악의 기능을합니다. 이것은 드문 시나리오이지만 일어날 수 있다고 생각합니다.
def py2sort(iterable):
by_type_repr = lambda x: repr(type(x))
iterable = sorted(iterable, key = by_type_repr)
types = {type_: list(group) for type_, group in groupby(iterable, by_type_repr)}
def merge_compatible_types(types):
representatives = [(type_, items[0]) for (type_, items) in types.items()]
def mergable_types():
for i, (type_0, elem_0) in enumerate(representatives, 1):
for type_1, elem_1 in representatives[i:]:
if _comparable(elem_0, elem_1):
yield type_0, type_1
def merge_types(a, b):
try:
types[a].extend(types[b])
del types[b]
except KeyError:
pass # already merged
for a, b in mergable_types():
merge_types(a, b)
return types
def gen_from_sorted_comparable_groups(types):
for _, items in types.items():
try:
items = sorted(items)
except TypeError:
pass #unorderable type
yield from items
types = merge_compatible_types(types)
return list(gen_from_sorted_comparable_groups(types))
def _comparable(x, y):
try:
x < y
except TypeError:
return False
else:
return True
if __name__ == '__main__':
print('before py2sort:')
test = [2, -11.6, 3, 5.0, (1, '5', 3), (object, object()), complex(2, 3), [list, tuple], Fraction(11, 2), '2', type, str, 'foo', object(), 'bar']
print(test)
print('after py2sort:')
print(py2sort(test))
나는 대상 시스템을 자세히 설명하면서 이런 종류의 작업 (이것에 매우 가까운 다른 시스템의 동작을 모방하는 것과 같은)을 시작하는 것이 좋습니다. 다른 코너 케이스에서 어떻게 작동해야합니까? 이를 수행하는 가장 좋은 방법 중 하나는 올바른 동작을 보장하기 위해 여러 테스트를 작성하는 것입니다. 이러한 테스트를 받으면 다음을 얻을 수 있습니다.
- 어떤 요소가 어떤 요소 앞에 와야하는지 더 잘 이해
- 기본 문서화
- 일부 리팩토링 및 기능 추가에 대해 시스템을 견고하게 만듭니다. 예를 들어 규칙이 하나 더 추가되면 이전 규칙이 깨지지 않도록하는 방법은 무엇입니까?
다음과 같은 테스트 케이스를 작성할 수 있습니다.
sort2_test.py
import unittest
from sort2 import sorted2
class TestSortNumbers(unittest.TestCase):
"""
Verifies numbers are get sorted correctly.
"""
def test_sort_empty(self):
self.assertEqual(sorted2([]), [])
def test_sort_one_element_int(self):
self.assertEqual(sorted2([1]), [1])
def test_sort_one_element_real(self):
self.assertEqual(sorted2([1.0]), [1.0])
def test_ints(self):
self.assertEqual(sorted2([1, 2]), [1, 2])
def test_ints_reverse(self):
self.assertEqual(sorted2([2, 1]), [1, 2])
class TestSortStrings(unittest.TestCase):
"""
Verifies numbers are get sorted correctly.
"""
def test_sort_one_element_str(self):
self.assertEqual(sorted2(["1.0"]), ["1.0"])
class TestSortIntString(unittest.TestCase):
"""
Verifies numbers and strings are get sorted correctly.
"""
def test_string_after_int(self):
self.assertEqual(sorted2([1, "1"]), [1, "1"])
self.assertEqual(sorted2([0, "1"]), [0, "1"])
self.assertEqual(sorted2([-1, "1"]), [-1, "1"])
self.assertEqual(sorted2(["1", 1]), [1, "1"])
self.assertEqual(sorted2(["0", 1]), [1, "0"])
self.assertEqual(sorted2(["-1", 1]), [1, "-1"])
class TestSortIntDict(unittest.TestCase):
"""
Verifies numbers and dict are get sorted correctly.
"""
def test_string_after_int(self):
self.assertEqual(sorted2([1, {1: 2}]), [1, {1: 2}])
self.assertEqual(sorted2([0, {1: 2}]), [0, {1: 2}])
self.assertEqual(sorted2([-1, {1: 2}]), [-1, {1: 2}])
self.assertEqual(sorted2([{1: 2}, 1]), [1, {1: 2}])
self.assertEqual(sorted2([{1: 2}, 1]), [1, {1: 2}])
self.assertEqual(sorted2([{1: 2}, 1]), [1, {1: 2}])
다음은 다음과 같은 정렬 기능을 가질 수 있습니다.
sort2.py
from numbers import Real
from decimal import Decimal
from itertools import tee, filterfalse
def sorted2(iterable):
"""
:param iterable: An iterable (array or alike)
entity which elements should be sorted.
:return: List with sorted elements.
"""
def predicate(x):
return isinstance(x, (Real, Decimal))
t1, t2 = tee(iterable)
numbers = filter(predicate, t1)
non_numbers = filterfalse(predicate, t2)
sorted_numbers = sorted(numbers)
sorted_non_numbers = sorted(non_numbers, key=str)
return sorted_numbers + sorted_non_numbers
사용법은 매우 간단하며 테스트에 문서화되어 있습니다.
>>> from sort2 import sorted2
>>> sorted2([1,2,3, "aaa", {3:5}, [1,2,34], {-8:15}])
[1, 2, 3, [1, 2, 34], 'aaa', {-8: 15}, {3: 5}]
가능한 한 충실하게 파이썬 3에서 파이썬 2 정렬 c 코드를 구현하려고했습니다.
그래서처럼 사용 mydata.sort(key=py2key())
하거나mydata.sort(key=py2key(lambda x: mykeyfunc))
def default_3way_compare(v, w): # Yes, this is how Python 2 sorted things :)
tv, tw = type(v), type(w)
if tv is tw:
return -1 if id(v) < id(w) else (1 if id(v) > id(w) else 0)
if v is None:
return -1
if w is None:
return 1
if isinstance(v, (int, float)):
vname = ''
else:
vname = type(v).__name__
if isinstance(w, (int, float)):
wname = ''
else:
wname = type(w).__name__
if vname < wname:
return -1
if vname > wname:
return 1
return -1 if id(type(v)) < id(type(w)) else 1
def py2key(func=None): # based on cmp_to_key
class K(object):
__slots__ = ['obj']
__hash__ = None
def __init__(self, obj):
self.obj = func(obj) if func else obj
def __lt__(self, other):
try:
return self.obj < other.obj
except TypeError:
return default_3way_compare(self.obj, other.obj) < 0
def __gt__(self, other):
try:
return self.obj > other.obj
except TypeError:
return default_3way_compare(self.obj, other.obj) > 0
def __eq__(self, other):
try:
return self.obj == other.obj
except TypeError:
return default_3way_compare(self.obj, other.obj) == 0
def __le__(self, other):
try:
return self.obj <= other.obj
except TypeError:
return default_3way_compare(self.obj, other.obj) <= 0
def __ge__(self, other):
try:
return self.obj >= other.obj
except TypeError:
return default_3way_compare(self.obj, other.obj) >= 0
return K
이를 수행하는 한 가지 방법은 다음과 같습니다.
lst = [0, 'one', 2.3, 'four', -5]
a=[x for x in lst if type(x) == type(1) or type(x) == type(1.1)]
b=[y for y in lst if type(y) == type('string')]
a.sort()
b.sort()
c = a+b
print(c)
@ martijn-pieters python2의 목록에 __cmp__
목록 객체 비교를 처리하거나 python2에서 처리하는 방법이 있는지 모르겠습니다 .
어쨌든 @ martijn-pieters의 답변 외에도 다음 목록 비교기를 사용했기 때문에 적어도 동일한 입력 세트에서 요소의 다른 순서를 기반으로 다른 정렬 된 출력을 제공하지 않습니다.
@per_type_cmp(list) def list_cmp(a, b): for a_item, b_item in zip(a, b): if a_item == b_item: continue return python2_sort_key(a_item) < python2_sort_key(b_item) return len(a) < len(b)
따라서 Martijn의 원래 답변과 결합하십시오.
from numbers import Number
# decorator for type to function mapping special cases
def per_type_cmp(type_):
try:
mapping = per_type_cmp.mapping
except AttributeError:
mapping = per_type_cmp.mapping = {}
def decorator(cmpfunc):
mapping[type_] = cmpfunc
return cmpfunc
return decorator
class python2_sort_key(object):
_unhandled_types = {complex}
def __init__(self, ob):
self._ob = ob
def __lt__(self, other):
_unhandled_types = self._unhandled_types
self, other = self._ob, other._ob # we don't care about the wrapper
# default_3way_compare is used only if direct comparison failed
try:
return self < other
except TypeError:
pass
# hooks to implement special casing for types, dict in Py2 has
# a dedicated __cmp__ method that is gone in Py3 for example.
for type_, special_cmp in per_type_cmp.mapping.items():
if isinstance(self, type_) and isinstance(other, type_):
return special_cmp(self, other)
# explicitly raise again for types that won't sort in Python 2 either
if type(self) in _unhandled_types:
raise TypeError('no ordering relation is defined for {}'.format(
type(self).__name__))
if type(other) in _unhandled_types:
raise TypeError('no ordering relation is defined for {}'.format(
type(other).__name__))
# default_3way_compare from Python 2 as Python code
# same type but no ordering defined, go by id
if type(self) is type(other):
return id(self) < id(other)
# None always comes first
if self is None:
return True
if other is None:
return False
# Sort by typename, but numbers are sorted before other types
self_tname = '' if isinstance(self, Number) else type(self).__name__
other_tname = '' if isinstance(other, Number) else type(other).__name__
if self_tname != other_tname:
return self_tname < other_tname
# same typename, or both numbers, but different type objects, order
# by the id of the type object
return id(type(self)) < id(type(other))
@per_type_cmp(dict)
def dict_cmp(a, b, _s=object()):
if len(a) != len(b):
return len(a) < len(b)
adiff = min((k for k in a if a[k] != b.get(k, _s)), key=python2_sort_key, default=_s)
if adiff is _s:
# All keys in a have a matching value in b, so the dicts are equal
return False
bdiff = min((k for k in b if b[k] != a.get(k, _s)), key=python2_sort_key)
if adiff != bdiff:
return python2_sort_key(adiff) < python2_sort_key(bdiff)
return python2_sort_key(a[adiff]) < python2_sort_key(b[bdiff])
@per_type_cmp(list)
def list_cmp(a, b):
for a_item, b_item in zip(a, b):
if a_item == b_item:
continue
return python2_sort_key(a_item) < python2_sort_key(b_item)
return len(a) < len(b)
추신 : 댓글로 작성하는 것이 더 합리적이지만 댓글을 달 수있는 평판이 충분하지 않았습니다. 그래서 대신 답으로 만들고 있습니다.
참조 URL : https://stackoverflow.com/questions/26575183/how-can-i-get-2-x-like-sorting-behaviour-in-python-3-x
'programing' 카테고리의 다른 글
다른 파이썬 로그 핸들러에 대해 다른 수준을 설정하는 방법 (0) | 2021.01.15 |
---|---|
이중 피벗 퀵 정렬과 퀵 정렬의 차이점은 무엇입니까? (0) | 2021.01.15 |
Swift의 일반 유형 별칭 (0) | 2021.01.15 |
C # : 형식의 모든 공용 (가져 오기 및 설정 모두) 문자열 속성을 가져 오는 방법 (0) | 2021.01.14 |
python / matplotlib의 세로 레이블이있는 Barchart (0) | 2021.01.14 |