2012-07-17 7 views
2

정렬과 함께 사용할 수있는 Perl 비교 함수가 필요합니다.정렬을위한 하위 키 비교 함수

각 키는 구분 문자 (점, 콜론, 공백 및 슬래시)로 구분 된 임의의 수의 하위 키가있는 텍스트 문자열입니다. 일부 하위 키는 숫자이며 숫자로 정렬해야합니다. 키 형식 및 하위 키 수는 다양합니다. 따라서 비교는 하나의 키가 다른 키보다 길게 처리해야하며 하위 키가 한 키에서는 숫자이지만 다른 키에서는 그렇지 않은 경우를 처리해야합니다.이 경우 텍스트 비교가 해당 하위 키에 적합합니다.

이 작동하지만, 나는 거기에 더 나은 솔루션을 내기 : 내 목적을 위해

use warnings; 
use strict; 
use Scalar::Util qw[looks_like_number]; 

sub hier_cmp { 

    my $aa = $a; 
    my $bb = $b; 

    # convert all delims (. :/space) to the same delim 

    $aa =~ tr/.:\/ /::::/; 
    $bb =~ tr/.:\/ /::::/; 
    my @lista = split(":", $aa); 
    my @listb = split(":", $bb); 

    my $result; 

    for my $ix (0 .. min($#lista, $#listb)) { 
     if (exists($lista[$ix]) && exists($listb[$ix])) { 
      if (looks_like_number($lista[$ix]) && looks_like_number($listb[$ix])) { 
       # compare numerically 
       $result = ($lista[$ix] <=> $listb[$ix]); 
      } else { 
       # compare as strings 
       $result = ($lista[$ix] cmp $listb[$ix]); 
      } 
      if ($result == 0) { 
       next; 
      } 
      return $result; 

     } elsif (exists($lista[$ix])) { 
      return 1; 
     } else { 
      return -1; 
     } 
    } 
} 

는 가독성은 속도보다 더 중요하다. 이는 내부 도구 용 일 ​​뿐이며 목록에는 거의 수백 가지 요소가 포함되지 않습니다. 그러나, 어떤 것을 배울 기회는 좋습니다.

보시다시피 필자는 펄 마법사가 아닙니다. 심지어 내 코드에 대한 사소한 향상도 인정 될 것이다.

감사합니다.

+1

:'내 @lista = 분할 m {[/.]} $의 AA,' – toolic

+1

당신이 정렬 할 데이터의 샘플을 공유 할 수 있습니까? – Kenosis

+1

FWIW 다른 하위 키 목록이 더 길지만 현재까지는 동일하지 않은 경우 하위 키 비교가 더 짧은 하위 키 목록의 최종 인덱스에서 잘못 중지됩니다. '사용 특징 qw (말하기) 비교; 'sort hier_cmp qw (foo : bar foo)'라고 말하면서 hier_cmp qw (foo foo : bar)를 말하십시오. – pilcrow

답변

1

당신이 우리와 함께 테스트하기 위해 일부 데이터를 준 경우 도움이 될,하지만이 코드는 몇 가지 기본적인 테스트를 통과하고 바로 보인다.

List::MoreUtils 함수 pairwise을 사용하여 필드 쌍 배열을 만들어 문제를 간단하게 만듭니다.

다음 중 하나만 정의되어 있는지, 목록 중 하나가 다른 것보다 끝나고 먼저 정렬되어야하는지 여부를 확인하는 것입니다. 둘 다 숫자 일 경우 숫자 비교와 비교해야합니다. 그렇지 않으면 단순히 문자열로 비교하십시오.

쌍의 배열 끝에 도달하면 모든 것이 일치하고 동등성을 나타 내기 위해 0이 반환됩니다.

업데이트

나는 List::MoreUtils::pairwise에 대한 종속성을 제거하려면이 코드를 변경했습니다.

use strict; 
use warnings; 

use Scalar::Util 'looks_like_number'; 

sub hier_cmp { 

    our ($a, $b); 

    my @a = split m|[.: /]+|, $a; 
    my @b = split m|[.: /]+|, $b; 

    for my $i (0 .. $#a > $#b ? $#a : $#b) { 
    my @ab = ($a[$i], $b[$i]); 
    if (grep defined, @ab < 2) { 
     return defined $ab[0] ? 1 : -1; 
    } 
    else { 
     my $numeric = grep(looks_like_number($_), @ab) == 2; 
     my $result = $numeric ? $ab[0] <=> $ab[1] : $ab[0] cmp $ab[1]; 
     return $result if $result; 
    } 
    } 

    return 0; 
} 
여러 분리 문자에 분할 할 수 있습니다
+0

감사합니다. 매우 유용합니다. 다시 불행히도, 서버에는 List :: MoreUtils가 없습니다. –

+0

그런 다음 모듈을 별도로 다운로드하고 코드를 복사하십시오. 그것은 단지 몇 줄에 불과합니다. – Borodin

+0

아 좋은 지적이야! :-) –

2

자연 정렬과 비슷합니다. CPAN에는 이미 Sort::Naturally 또는 Sort::Key::Natural과 같은 모듈이 여러 개 있습니다. 예를 들어

:

use Sort::Key::Natural qw(natsort); 
my @sorted = natsort @data; 
+0

감사합니다. 불행히도 이러한 모듈은 서버에서 사용할 수 없으므로 사용해야하며 제어 할 수 없습니다. –