Tips in Action‎ > ‎문자열‎ > ‎

원하는 방법으로 정렬하기

전종필

배열이나 목록을 정렬(sort)하기 위해 sort 함수를 사용합니다.

@arr = qw( 1 3 6 9 10 30 2 25 );
@sortarr = sort @arr; # 1 10 2 25 3 30 6 9 순으로 정렬됨
사실, 위의 sort 사용은 다음과 똑같은 내용입니다.

@sortarr = sort { $a cmp $b } @arr;
sort 토큰과 배열 사이에 실행블록이 들어가면, 각 요소에 대한 비교를 행할 때, 그 실행블록을 사용하게 됩니다. 이 때, $a는 비교하는 두 값 중 앞의 것을 의미하고, $b는 뒤의 것을 의미하며, 실행블록의 결과가 -1이면 앞의 것($a)이 작은 것이고, 1이면 뒤의 것($b)이 작은 것이며, 0이면 서로 같은 것으로 판단하여 정렬합니다.
그러나, 이 비교방법은 cmp연산자를 사용하므로, ASCII값을 비교하기 때문에, 숫자들의 배열인 경우에는 (대부분의 경우에는) 원치않는 결과가 나옵니다.
만일 원하는 정렬방법이 숫자로서의 정렬이라면, 다음과 같이 실행블록을 사용하여 원하는 방법을 지정해 줍니다.

@arr = qw( 1 3 6 9 10 30 2 25 );
@sortarr = sort { $a <=> $b } @arr; # 결과는 직접해서 보시길...
위 실행블록은 cmp 대신에 <=>연산자를 사용하므로 숫자간의 비교를 해 주어 원하는 대로 숫자값을 이용한 정렬이 가능하게 됩니다.
또, 만일 역 방향으로(큰 값에서 작은 값으로) 정렬하고자 한다면, $a와 $b를 바꾸어 줍니다.

@arr = qw( 1 3 6 9 10 30 2 25 );
@sortarr = sort { $b <=> $a } @arr; # 30 25 10 9 6 3 2 1
@sortarr = sort { $b cmp $a } @arr; # 9 6 30 3 25 2 10 1
물론 실행블록 안에서는 어떤 것도 사용할 수 있고, 서브루틴도 사용할 수 있습니다.

@sortarr = sort { &cmp_ip($a,$b) } @ip_address;

sub cmp_ip {
	my($aip,$bip) = @_;
	return sprintf("%03d.%03d.%03d.%03d",split(/\./,$aip))
		cmp sprintf("%03d.%03d.%03d.%03d",split(/\./,$bip))
}
Comments