커스텀 Python 목록 정렬


96

나는 내 오래된 코드를 리팩토링하고 있었고 이것을 발견했습니다.

alist.sort(cmp_items)

def cmp_items(a, b):
    if a.foo > b.foo:
        return 1
    elif a.foo == b.foo:
        return 0
    else:
        return -1

코드는 작동하지만 (약 3 년 전에 작성했습니다!) Python 문서의 어느 곳에서도이 문서를 찾을 수 없으며 모두가 sorted()사용자 지정 정렬을 구현하는 데 사용 합니다. 누군가 이것이 왜 작동하는지 설명 할 수 있습니까?


sorted()sort()거의 같은 방법으로 정렬 제공 정의는, 호출 규칙의 차이를 모듈로.
Russell Borogove 2012-08-07

2
실제로 일어나는 일은 key매개 변수 를 사용하는 것이 cmp함수 를 전달하는 것보다 선호 된다는 것입니다. (후자의 경우에도 3 파이썬에서 구현되지 않음)
jsbueno

목록에있는 항목이 무엇인지에 따라 다소 모호합니다. 코드에 속성이 있어야 foo합니다. 그렇지 않으면 폭발합니다. 더 나은 사용자 정의 정의 __lt__()다음 수업을위한 방법 sorted()list.sort()아웃 - 오브 - 박스 작동합니다. (, BTW 정의 할 이상 필요 객체없는 __cmp__()단지를 __lt__(). 이 참조
SMCI

답변:


60

여기에 문서화되어 있습니다 .

sort () 메서드는 비교를 제어하기위한 선택적 인수를 사용합니다.

cmp는 첫 번째 인수가 두 번째 인수보다 작은 지, 같은지 또는 큰지 여부에 따라 음수, 0 또는 양수를 반환해야하는 두 인수 (목록 항목)의 사용자 지정 비교 함수를 지정합니다. cmp = lambda x, y : cmp (x.lower (), y.lower ()). 기본값은 없음입니다.


덕분에 내가 여기에 확인하고 있었고, 메소드 서명에서 볼 수없는 miles82 docs.python.org/tutorial/datastructures.html
로렌조

링크 한 페이지에 동일한 텍스트가 표시되지 않습니다. 문서가 변경 되었습니까? 게다가을 사용하려고 cmp하면 TypeError: 'cmp' is an invalid keyword argument for this function. 여기서 무슨 일이 일어나고 있습니까?
HelloGoodbye

1
@HelloGoodbye sort ()에는 Python 3에 cmp 인수가 없습니다. 이것은 문서 링크가 Python 2 용이었을 때의 오래된 답변 입니다. 여기 에서 이전 문서를 찾 거나 여기에서 자세한 내용을 읽을 수 있습니다 . Python 3을 사용하는 경우 대신 key 인수를 사용합니다.
miles82

실제로 비교 기능을 제공하려면 어떻게해야합니까? 문자열의 숫자 (모든 길이, 탐욕스럽게 선택됨)를 개별 문자가 다르게 취급되는 방식과 동일하게 기호로 취급하고 싶습니다. 비교 기능을 제공 할 수 있다면 사소하게 달성하는 방법을 알고 있지만 핵심 기능을 제공해야하는 경우에는 그렇지 않습니다. 이것이 변경된 이유는 무엇입니까?
HelloGoodbye

문자열에 포함 된 각 숫자가 Levenshtein coding 과 같이 사전 순으로 숫자를 정렬하는 인코딩을 사용하여 인코딩되면 여전히 달성 할 수 있다고 생각합니다 . 그러나 나는 사실을 해결 등이 더 생각 sort나는 것이 무엇인가 파이썬 3 인자로 비교 기능을, 그리고하지 않습니다 실제로 할 싶습니다.
HelloGoodbye

108

참고로 다음은 동일한 정렬을 구현하는 더 나은 대안입니다.

alist.sort(key=lambda x: x.foo)

또는 :

import operator
alist.sort(key=operator.attrgetter('foo'))

Sorting How To를 확인하십시오 . 매우 유용합니다.


1
연산자에 대한 TIL, 매우 유용합니다.
ffledgling

15

이 예처럼. 이 목록을 정렬하고 싶습니다.

[('c', 2), ('b', 2), ('a', 3)]

산출:

[('a', 3), ('b', 2), ('c', 2)]

두 번째 항목을 기준으로 튜플을 정렬 한 다음 첫 번째 항목을 정렬해야합니다.

def letter_cmp(a, b):
    if a[1] > b[1]:
        return -1
    elif a[1] == b[1]:
        if a[0] > b[0]:
            return 1
        else:
            return -1
    else:
        return 1

그런 다음 키 함수로 변환하십시오.

from functools import cmp_to_key
letter_cmp_key = cmp_to_key(letter_cmp))

이제 사용자 지정 정렬 순서를 사용할 수 있습니다.

[('c', 2), ('b', 2), ('a', 3)].sort(key=letter_cmp_key)

4
정렬 할 목록을 어떻게 알 수 있습니까?
Cameron Monks 2019

2
@CameronMonks yourList.sort (letter_cmp)
Minyc510

7

이것은 Python 3에서 작동하지 않습니다.

functools cmp_to_key를 사용하여 이전 스타일의 비교 함수가 작동하도록 할 수 있습니다.

from functools import cmp_to_key

def cmp_items(a, b):
    if a.foo > b.foo:
        return 1
    elif a.foo == b.foo:
        return 0
    else:
        return -1

cmp_items_py3 = cmp_to_key(cmp_items)

alist.sort(cmp_items_py3)

1

많은 사람들이 이미 좋은 답변을 올렸다는 것을 알고 있습니다. 그러나 라이브러리를 가져 오지 않고 멋지고 쉬운 방법을 제안하고 싶습니다.

l = [(2, 3), (3, 4), (2, 4)]
l.sort(key = lambda x: (-x[0], -x[1]) )
print(l)
l.sort(key = lambda x: (x[0], -x[1]) )
print(l)

출력은

[(3, 4), (2, 4), (2, 3)]
[(2, 4), (2, 3), (3, 4)]

출력은 튜플 형식으로 제공 한 매개 변수의 순서에 따라 정렬됩니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.