Quick Syntax
Array.Sort(arr);
Array.Sort(arr, (a, b) => a.CompareTo(b));
list.Sort();
list.Sort((a, b) => b.Score.CompareTo(a.Score)); // 내림차순
var sorted = items
.OrderBy(x => x.Group)
.ThenByDescending(x => x.Score)
.ToList();원본을 바꿔도 되면 Array.Sort·List<T>.Sort, 새 시퀀스와 다단계 기준이 필요하면 OrderBy를 고릅니다. 비교 함수는 뺄셈 대신 CompareTo로 작성합니다.
문법
| API | 대상 | 원본 변경 | 특징 |
|---|---|---|---|
Array.Sort | 배열 | 변경함 | 빠르고 직접적 |
List<T>.Sort | 리스트 | 변경함 | 리스트 내부 정렬 |
OrderBy | IEnumerable<T> | 새 시퀀스 | 체이닝이 편함 |
ThenBy | OrderBy 결과 | 새 시퀀스 | 2차 정렬 기준 |
배열과 리스트를 제자리에서 정렬할 때는 Sort를 씁니다. 정렬 결과를 새 컬렉션으로 받고 싶거나 여러 기준을 읽기 쉽게 연결하고 싶으면 LINQ가 편합니다.
OrderBy는 호출 즉시 배열을 만드는 것이 아니라 열거할 때 정렬을 수행합니다. 결과를 한 번 고정해 여러 번 쓸 때는 ToArray나 ToList로 materialize하고, 한 번만 순회하는 코테 코드에서는 불필요한 중간 컬렉션을 만들지 않는 편이 낫습니다.
비교 함수
비교 함수는 왼쪽 값 a가 먼저 와야 하면 음수, 같으면 0, 뒤에 와야 하면 양수를 반환합니다.
people.Sort((a, b) =>
{
int byAge = a.Age.CompareTo(b.Age);
if (byAge != 0) return byAge;
return string.Compare(a.Name, b.Name, StringComparison.Ordinal);
});숫자를 비교할 때 a - b를 반환하는 방식은 overflow 위험이 있습니다. CompareTo를 쓰는 편이 안전합니다.
비교 함수는 같은 두 값에 같은 결과를 내고, a < b, b < c이면 a < c가 되도록 일관되어야 합니다. 외부에서 바뀌는 상태나 culture에 따라 결과가 흔들리면 정렬 결과가 예측할 수 없게 됩니다. 식별자처럼 고정된 규칙이 필요하면 StringComparison.Ordinal을 명시합니다.
정렬 기준
| 목표 | 예시 |
|---|---|
| 오름차순 | a.CompareTo(b) |
| 내림차순 | b.CompareTo(a) |
| 1차 오름차순, 2차 내림차순 | OrderBy(...).ThenByDescending(...) |
| 문자열 사전순 | string.Compare(a, b, StringComparison.Ordinal) |
| 튜플 정렬 | (a.X, a.Y).CompareTo((b.X, b.Y)) |
Array.Sort(points, (a, b) =>
{
int byX = a.X.CompareTo(b.X);
if (byX != 0) return byX;
return a.Y.CompareTo(b.Y);
});주의할 점
Array.Sort와 List<T>.Sort는 stable 정렬을 보장하지 않습니다. 같은 키의 기존 순서가 중요하면 LINQ OrderBy 계열처럼 stable 정렬을 제공하는 API를 검토하세요.
또 OrderBy(...).OrderBy(...)를 연속으로 쓰면 앞 정렬 기준이 새 정렬로 덮이는 형태가 됩니다. 2차 기준은 ThenBy, ThenByDescending으로 이어야 합니다.
참고 링크
3 sources