두 개의 필드로 파이썬리스트 정렬


172

정렬 된 CSV로 만든 다음 목록이 있습니다.

list1 = sorted(csv1, key=operator.itemgetter(1))

실제로 목록을 두 가지 기준으로 정렬하고 싶습니다. 먼저 필드 1의 값을 기준으로 한 다음 필드 2의 값을 기준으로 정렬합니다. 어떻게해야합니까?



우리는이 질문을 견디고 그 범위를 "길이-목록-길이-내장 유형 (예 : string / int / float)"으로 제한합니까 ? 또는 제목에서 알 수 있듯이 "사용자 정의 객체 목록" 도 허용 합니까? 이 경우 대답은 " __lt__()클래스에서 메소드 정의 또는 일부 클래스에서 상속"입니다 . 그것은 훨씬 더 나은 정식으로 만들 것입니다.
smci

답변:


157

이처럼 :

import operator
list1 = sorted(csv1, key=operator.itemgetter(1, 2))

1
+1 : 내 것보다 더 우아합니다. itemgetter가 여러 인덱스를 가질 수 있다는 것을 잊었습니다.
dappawit

7
operator가져와야하는 모듈입니다.
trapicki

3
itemgetter를 사용하여 한 요소에서 오름차순으로 정렬하고 다른 요소에서 내림차순으로 정렬하려면 어떻게 진행합니까?
ashish

3
@ashish, 람다 함수를 사용하여 아래의 답변을 참조하십시오. 명확하다면 "-x [1]"또는 "x [0] + x [1]"로
정렬하십시오.

역 모드에서 하나의 기준이 있다면 어떨까요?
YaserKH

328

람다 함수를 사용할 때 아무 것도 가져올 필요가 없습니다.
다음 list은 첫 번째 요소를 기준으로 정렬 한 다음 두 번째 요소를 기준으로 정렬 합니다.

sorted(list, key=lambda x: (x[0], -x[1]))

12
좋은. 위의 주요 답변에 대한 의견에서 언급했듯이, 이것은 다른 정렬 순서로 여러 정렬을 수행하는 가장 좋은 방법입니다. 아마도 그것을 강조하십시오. 또한 텍스트에는 두 번째 요소에서 내림차순으로 정렬되었음을 나타내지 않습니다.
PeterVermont

2
@ user1700890 필드가 이미 문자열이라고 가정했습니다. 기본적으로 문자열을 알파벳 순서로 정렬해야합니다. 여기에 대한 답변 또는 OP의 원래 질문과 특별히 관련이없는 경우 자체 질문을 SO에 별도로 게시해야합니다.
pbible 2016

5
뭐라고합니까 -에서 -x[1]독립을 위해?
jan

7
@jan 그것은 역순입니다
jaap

3
특정한 경우에는 작동하지 않습니다. 허용 된 솔루션도 작동하지 않습니다. 예를 들어, 키로 사용되는 열은 숫자로 변환 할 수없는 모든 문자열입니다. 둘째, 하나의 열을 기준으로 오름차순으로 정렬하고 다른 열을 기준으로 내림차순으로 정렬하려고합니다.
coder.in.me

20

파이썬은 안정적인 정렬을 가지고 있으므로 성능이 문제가되지 않는 가장 간단한 방법은 필드 2로 정렬 한 다음 필드 1로 다시 정렬하는 것입니다.

그것은 당신에게 당신이 원하는 결과를 줄 것입니다, 유일한 캐치는 그것이 큰 목록이라면 (또는 당신이 그것을 자주 정렬하고 싶다면) sort를 두 번 호출하는 것은 용납 할 수없는 오버 헤드 일 수 있다는 것입니다.

list1 = sorted(csv1, key=operator.itemgetter(2))
list1 = sorted(list1, key=operator.itemgetter(1))

이 방법을 사용하면 일부 열의 역 정렬을 원하는 상황을 쉽게 처리 할 수 ​​있으며 필요한 경우 'reverse = True'매개 변수 만 포함하면됩니다.

그렇지 않으면 여러 매개 변수를 itemgetter에 전달하거나 수동으로 튜플을 빌드 할 수 있습니다. 아마 더 빠를 지 모르지만 일부 열이 역 정렬되기를 원한다면 잘 일반화되지 않는다는 문제가 있습니다 (숫자 열은 무시하여 정렬 할 수는 있지만 정렬이 안정적이지 않습니다).

따라서 역 정렬 된 열이 필요하지 않으면 여러 인수를 itemgetter로 이동하십시오. 가능한 경우 열이 숫자가 아니거나 여러 연속 정렬을 위해 정렬을 안정적으로 유지하려고합니다.

편집 : 이것이 원래의 질문에 어떻게 대답하는지 이해하는 데 어려움을 겪는 주석가의 경우, 정렬의 안정적인 특성으로 각 키에 대해 개별 정렬을 수행하고 여러 기준으로 정렬 된 데이터로 끝내는 방법을 정확하게 보여주는 예가 있습니다.

DATA = [
    ('Jones', 'Jane', 58),
    ('Smith', 'Anne', 30),
    ('Jones', 'Fred', 30),
    ('Smith', 'John', 60),
    ('Smith', 'Fred', 30),
    ('Jones', 'Anne', 30),
    ('Smith', 'Jane', 58),
    ('Smith', 'Twin2', 3),
    ('Jones', 'John', 60),
    ('Smith', 'Twin1', 3),
    ('Jones', 'Twin1', 3),
    ('Jones', 'Twin2', 3)
]

# Sort by Surname, Age DESCENDING, Firstname
print("Initial data in random order")
for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

print('''
First we sort by first name, after this pass all
Twin1 come before Twin2 and Anne comes before Fred''')
DATA.sort(key=lambda row: row[1])

for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

print('''
Second pass: sort by age in descending order.
Note that after this pass rows are sorted by age but
Twin1/Twin2 and Anne/Fred pairs are still in correct
firstname order.''')
DATA.sort(key=lambda row: row[2], reverse=True)
for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

print('''
Final pass sorts the Jones from the Smiths.
Within each family members are sorted by age but equal
age members are sorted by first name.
''')
DATA.sort(key=lambda row: row[0])
for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

이것은 실행 가능한 예제이지만 실행하는 사람들을 저장하기 위해 출력은 다음과 같습니다.

Initial data in random order
Jones      Jane       58
Smith      Anne       30
Jones      Fred       30
Smith      John       60
Smith      Fred       30
Jones      Anne       30
Smith      Jane       58
Smith      Twin2      3
Jones      John       60
Smith      Twin1      3
Jones      Twin1      3
Jones      Twin2      3

First we sort by first name, after this pass all
Twin1 come before Twin2 and Anne comes before Fred
Smith      Anne       30
Jones      Anne       30
Jones      Fred       30
Smith      Fred       30
Jones      Jane       58
Smith      Jane       58
Smith      John       60
Jones      John       60
Smith      Twin1      3
Jones      Twin1      3
Smith      Twin2      3
Jones      Twin2      3

Second pass: sort by age in descending order.
Note that after this pass rows are sorted by age but
Twin1/Twin2 and Anne/Fred pairs are still in correct
firstname order.
Smith      John       60
Jones      John       60
Jones      Jane       58
Smith      Jane       58
Smith      Anne       30
Jones      Anne       30
Jones      Fred       30
Smith      Fred       30
Smith      Twin1      3
Jones      Twin1      3
Smith      Twin2      3
Jones      Twin2      3

Final pass sorts the Jones from the Smiths.
Within each family members are sorted by age but equal
age members are sorted by first name.

Jones      John       60
Jones      Jane       58
Jones      Anne       30
Jones      Fred       30
Jones      Twin1      3
Jones      Twin2      3
Smith      John       60
Smith      Jane       58
Smith      Anne       30
Smith      Fred       30
Smith      Twin1      3
Smith      Twin2      3

특히 두 번째 단계에서 reverse=True매개 변수가 어떻게 이름을 순서대로 유지 하는가에 따라 목록을 정렬 한 후 뒤집 으면 세 번째 정렬 키에 대해 원하는 순서를 잃게됩니다.


1
안정적인 정렬은 이전 정렬이 무엇인지 잊지 않는다는 의미는 아닙니다. 이 답변은 잘못되었습니다.
Mike Axiak

7
안정적인 정렬은 열 c, b, a를 기준으로 정렬하여 열 a, b, c를 기준으로 정렬 할 수 있음을 의미합니다. 당신이 당신의 의견을 확장하려고하지 않는 한 나는 당신이 잘못 생각합니다.
Duncan

7
이 대답은 확실히 정확하지만 큰 목록의 경우 바람직하지 않습니다. 목록이 이미 부분적으로 정렬되어 있으면 목록을 훨씬 더 많이 섞어 파이썬 정렬의 최적화를 대부분 잃게됩니다. @ 마이크, 당신은 틀렸다; 실제로 답변을 잘못 선언하기 전에 답변을 테스트하는 것이 좋습니다.
Glenn Maynard

6
@MikeAxiak : docs.python.org/2/library/stdtypes.html#index-29 주석 9의 상태 9 : Python 2.3부터 sort () 메소드는 안정적으로 보장됩니다. 동일하게 비교되는 요소의 상대적 순서를 변경하지 않으면 정렬은 안정적입니다. 이는 여러 단계로 정렬하는 데 유용합니다 (예 : 부서별, 급여 등급별).
trapicki

이것이 그가 질문 한 질문에 답변하지 않기 때문에 이것은 정확하지 않습니다. 그는 첫 번째 인덱스로 정렬 된 목록을 원하고 첫 번째 인덱스에 관계가있는 경우 두 번째 인덱스를 정렬 기준으로 사용하려고합니다. 안정적인 정렬은 모든 것이 동일하다는 것을 보장하며, 원래의 주문은 항목이 나타나는 순서입니다.
Jon

14
list1 = sorted(csv1, key=lambda x: (x[1], x[2]) )

4
나는 생각하지 않는다 tuple()(당신이 계산하는 경우, 또는 오히려, 세 개의 인수를받을 수 있습니다 self)
필리페 코레

3
튜플 테이크는 오직 하나의 논쟁을 취할 수 있습니다
therealprashant

1
return진술은 return tuple((x[1], x[2]))또는 간단 해야합니다 return x[1], x[2]. 다른 방향으로 정렬하려면 아래 @jaap 답변을 참조하십시오.
Jo Kachikaran

… 또는 tuple(x[1:3])어떤 이유로 튜플 표시 목록 대신 튜플 생성자를 사용하려는 경우 x[1], x[2]. 또는 keyfunc = operator.itemgetter(1, 2)함수를 직접 작성하지 마십시오.
abarnert

3
employees.sort(key = lambda x:x[1])
employees.sort(key = lambda x:x[0])

파이썬 정렬이 제자리에 있고 안정적이기 때문에 .sort를 lambda와 함께 2 번 사용할 수도 있습니다. 먼저 두 번째 요소 x [1]에 따라 목록을 정렬합니다. 그런 다음 첫 번째 요소 x [0] (가장 높은 우선 순위)을 정렬합니다.

employees[0] = Employee's Name
employees[1] = Employee's Salary

이것은 다음을 수행하는 것과 같습니다. employee.sort (key = lambda x : (x [0], x [1]))


1
아니요,이 정렬 규칙이 두 번째로 우선해야합니다.
CodeFarmer

1

오름차순으로 다음을 사용할 수 있습니다.

sorted_data= sorted(non_sorted_data, key=lambda k: (k[1],k[0]))

또는 내림차순으로 다음을 사용할 수 있습니다.

sorted_data= sorted(non_sorted_data, key=lambda k: (k[1],k[0]),reverse=True)

0

아래를 사용하여 dicts 목록을 정렬하면 첫 번째 열의 급여가 내림차순으로 정렬되고 두 번째 열이 연령으로 정렬됩니다.

d=[{'salary':123,'age':23},{'salary':123,'age':25}]
d=sorted(d, key=lambda i: (i['salary'], i['age']),reverse=True)

출력 : [{ 'salary': 123, 'age': 25}, { 'salary': 123, 'age': 23}]

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