Perl Language
정렬
수색…
소개
일의 목록을 정렬을 위해, 펄은 하나의 기능, 당연히 불리는이 sort
. 숫자, 모든 인코딩 수의 문자열, 중첩 된 데이터 구조 또는 객체 등 모든 종류의 항목을 정렬 할 수있을만큼 유연합니다. 그러나 유연성으로 인해 사용법을 배울 수있는 몇 가지 트릭과 관용구가 있습니다.
통사론
- 정렬 SUBNAME LIST
- 정렬 BLOCK LIST
- 정렬 목록
기본 어휘 정렬
@sorted = sort @list;
@sorted = sort { $a cmp $b } @list;
sub compare { $a cmp $b }
@sorted = sort compare @list;
위의 세 가지 예는 완전히 똑같습니다. 비교 함수 나 블록을 제공하지 않으면, sort
는 당신이 어휘 적으로 정렬 된 오른쪽리스트를 원한다고 가정합니다. 이것은 예측 가능한 순서로 데이터가 필요하고 언어의 정확성에 신경 쓰지 않는 경우에 보통 원하는 형식입니다.
sort
는 @list
에있는 항목 쌍을 Comparator 함수로 @list
합니다.이 함수는 어느 항목이 더 큰지 sort
합니다. cmp
연산자는 문자열에 대해 이것을 수행하는 반면 <=>
는 숫자에 대해 동일한 작업을 수행합니다. 비교기는 평균 n * log ( n ) 배로 매우 자주 호출됩니다. n 은 정렬 될 요소의 수이므로 빠른 것이 중요합니다. 이것은 sort
가 미리 정의 된 패키지 전역 변수 ( $a
와 $b
)를 사용하여 적절한 함수 매개 변수 대신 블록이나 함수와 비교할 요소를 전달합니다.
당신이 경우 use locale
, cmp
그것을 정렬합니다, 예를 들어, 계정으로 로케일 고유의 배열 순서를 취 Å
같은 A
덴마크 로케일에서하지만 후 Z
영어 또는 독일어 하나에. 그러나 더 복잡한 유니 코드 정렬 규칙을 고려하지 않으며 주문에 대한 제어도 제공하지 않습니다. 예를 들어 전화 번호부는 사전과 다르게 정렬되는 경우가 많습니다. 이 경우 Unicode::Collate
및 특히 Unicode::Collate::Locale
모듈을 사용하는 것이 좋습니다.
숫자 정렬
@sorted = sort { $a <=> $b } @list;
$a
와 $b
를 <=>
연산자와 비교하면 값이 문자 그대로 비교되지 않도록 수치 적으로 비교할 수 있습니다.
역순 정렬
@sorted = sort { $b <=> $a } @list;
@sorted = reverse sort { $a <=> $b } @list;
내림차순으로 항목을 정렬 $a
것은 비교기 블록에서 $b
와 $b
를 바꾸는 것만으로 간단히 달성 할 수 있습니다. 그러나 약간의 속도가 느리지 만 별도의 reverse
명확히하는 사람들이 있습니다.
Schwartzian 변환
이것은 아마도 항목의 정렬 순서가 값 비싼 함수에 의존하는 Perl의 함수 프로그래밍 기능을 사용하는 정렬 최적화의 가장 유명한 예제 일 것입니다.
# What you would usually do
@sorted = sort { slow($a) <=> slow($b) } @list;
# What you do to make it faster
@sorted =
map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [ $_, slow($_) ] }
@list;
첫 번째 예제의 문제점은 비교기가 매우 자주 호출되고 느린 함수를 계속 반복하여 사용하여 값을 다시 계산한다는 점입니다. 일반적인 예는 파일 이름별로 파일 이름을 정렬하는 것입니다.
use File::stat;
@sorted = sort { stat($a)->size <=> stat($b)->size } glob "*";
이것은 작동하지만 기껏해야 비교 당 두 번의 시스템 호출의 오버 헤드가 발생합니다. 최악의 경우 한 번 비교할 때마다 두 번씩 디스크에 가야하고 그 디스크는 다른 쪽의 오버로드 된 파일 서버에있을 수 있습니다. 행성.
Randall Schwartz의 트릭을 입력하십시오.
Schwartzian Transform은 기본적으로 bottom-to-top의 세 가지 함수를 통해 @list
. 첫 번째 map
은 각 항목을 원본 항목의 두 요소 목록과 느린 기능의 결과를 정렬 키로 변환하므로이 마지막 단계에서는 각 요소에 대해 slow()
한 번만 호출했습니다. 다음 sort
은 목록을보고 정렬 키에 간단하게 액세스 할 수 있습니다. 정렬 키는 신경 쓰지 않지만 원래 요소 만 정렬 된 순서로 필요하기 때문에 최종 map
은 @sort
에서받은 이미 정렬 된 목록에서 두 요소 목록을 @sort
첫 번째 멤버 목록을 반환합니다 .
대소 문자를 구분하지 않는 정렬
sort
대소 문자를 무시하게 만드는 전통적인 기법은 비교를 위해 문자열을 lc
또는 uc
에 전달하는 것입니다.
@sorted = sort { lc($a) cmp lc($b) } @list;
이것은 Perl 5의 모든 버전에서 작동하며 영어로는 충분합니다. uc
또는 lc
를 사용하는지 여부는 중요하지 않습니다. 그러나 그리스어 나 터키어 같은 대문자와 소문자가 1 : 1로 대응하지 않으므로 uc
나 lc
것을 사용 하느냐에 따라 다른 결과를 얻을 수 있습니다. 따라서, 펄 5.16 이상에서는 기능이라고 접는 경우가 fc
이러한 문제를 방지, 다 언어 정렬이를 사용해야합니다 그래서 현대 :
@sorted = sort { fc($a) cmp fc($b) } @list;