HOWTO · Rust
Rust에서 벡터 정렬
sort_by() 및 sort() 함수는 벡터를 참조하여 정렬하여 반환합니다. 값은 기본적으로 오름차순으로 정렬됩니다.
이 페이지의 내용
Rust에서 벡터를 오름차순으로 정렬하려면 가변 벡터에서 sort()를 호출하세요. 벡터의 요소는 제자리에서 재배열되며 자연 순서를 따릅니다. 특정 필드를 기준으로 비교하거나 다른 정렬 순서를 정의하려면 sort_by()를 사용하세요. 두 메서드 모두 Rust 표준 라이브러리에서 제공합니다.
sort()로 제자리에서 정렬하기
요소 타입에 자연스러운 전체 순서가 있다면 sort()를 사용하면 됩니다. 정렬 과정에서 요소가 재배열되므로 벡터는 가변이어야 합니다. 요소 타입은 Ord 트레이트를 구현해야 합니다. 정수와 문자열은 이를 구현하지만 부동소수점 타입은 구현하지 않습니다.
다음 예제를 실행해 보세요.
fn main() {
let mut numbers = vec![5, 3, 8, 1, 2];
numbers.sort();
println!("{:?}", numbers);
}
호출이 끝나면 numbers에는 같은 값이 오름차순으로 들어 있습니다. 이 메서드는 정렬된 새 벡터를 반환하는 대신 기존 벡터를 정렬하므로, 결과를 계속 사용하려면 가변 바인딩을 사용해야 합니다.
문자열 벡터에서도 sort()는 타입의 자연 순서를 따릅니다. 내림차순이 필요하면 비교 순서를 뒤집는 sort_by()를 사용하세요. 예를 들면 |a, b| b.cmp(a)와 같습니다. 자연 순서가 애플리케이션에서 값을 표시하거나 그룹화하는 방식과 다를 때는 원하는 순서를 명시적으로 선택하세요.
sort_by()로 사용자 지정 순서 적용하기
sort_by()는 비교 클로저를 받습니다. Rust는 두 요소를 클로저에 전달하고, 클로저는 Less, Equal, Greater 중 하나인 Ordering 값을 반환합니다. 즉, 요소마다 키 하나를 반환하는 키 함수가 아니라 요소 두 개를 서로 비교합니다. Ord를 구현하는 값의 cmp() 메서드를 사용하면 결과를 간편하게 만들 수 있습니다.
다음 예제는 튜플의 두 번째 필드를 기준으로 오름차순 정렬합니다.
fn main() {
let mut pairs = vec![(1, 3), (2, 1), (3, 2)];
pairs.sort_by(|a, b| a.1.cmp(&b.1));
println!("{:?}", pairs);
}
클로저는 a.1과 b.1을 비교하며 튜플 값 자체를 바꾸지는 않습니다. 여러 필드를 기준으로 정렬하려면 먼저 주요 필드를 비교하고, 값이 같을 때 다른 비교를 적용해 순서를 정하세요. 비교 클로저는 일관적이어야 합니다. 같은 값 쌍에 대해 안정적인 정렬 관계를 나타내야 합니다. sort_by()도 벡터를 제자리에서 변경하므로 가변 바인딩이 필요합니다.
부동소수점 값을 안전하게 정렬하기
Rust의 f32와 f64 타입은 Ord가 아니라 PartialOrd를 구현합니다. 대부분의 유한한 값끼리는 비교할 수 있지만, NaN이 포함된 비교는 순서 값을 만들지 못합니다. 따라서 부동소수점 벡터에 sort()를 바로 호출할 수 없으며, partial_cmp()의 결과를 무조건 언래핑하면 값이 NaN일 때 패닉이 발생할 수 있습니다.
부동소수점 값에 Rust의 전체 순서를 적용하려면 비교 클로저에서 total_cmp()를 사용하세요. 이 메서드는 NaN을 포함하는 순서를 정의하고 음의 0과 양의 0을 구별합니다. 다음 독립 실행형 예제는 NaN을 포함해 선택한 정책을 명확히 보여 줍니다.
fn main() {
let mut values = vec![3.5_f64, f64::NAN, -1.0, 2.0];
values.sort_by(f64::total_cmp);
println!("{:?}", values);
}
total_cmp()는 모든 부동소수점 값에 하나의 결정적인 순서를 적용해야 할 때 유용합니다. 애플리케이션에서 NaN을 모두 마지막에 두거나 아예 거부해야 한다면 비교 클로저에 해당 정책을 명시하거나 정렬 전에 데이터를 검증하세요. 전체 순서는 비교 규칙을 제공하지만, 데이터에 어떤 정책이 적합한지는 결정해 주지 않습니다.