2012-02-02 7 views
3

いくつかのファイルを注文するためにPerlでTcl辞書ソートを実装しようとしています。 Tclのを知らない人のために、あなたはそれが彼らの値で連続整数をソートするために取得することができ、ここで詳述だ:Odd Perl '辞書'ソートの振る舞い

http://www.perlmonks.org/index.pl?node_id=160157

を要約すると: の与えられた配列:

qw(
    bigbang 
    x10y 
    x9y 
    bigboy 
    bigBoy 
    x11y 
) 

を大文字と小文字を区別しない文字でソートされます。その後、タイブレイカーとして大文字と小文字が区別されます。その後は数字で区切られ、ソートでは単一の数字として解釈されます。

.

の前に現れるため、1にx10yとx11y上に表示されるx9yで

、標準のASCIIソートで、x10yとx11yがx9yの上に来るとしながら、私は関数としてそのリンクにJuerdの例を実装しようとしましたが、私の場合、私は以下のように、バージョン番号のリストを持っているソート完全に模倣したTcl辞書ソート:

qw{ 1 1.0 1.01 1.2 1.02 1.0003 1.102 1.103 1.203 102a 102b 103a 103b 123 }; 

しかし、絶対パスをファイルに使用されている場合、順序は台無し。

以下にサンプルスクリプトを掲載しました。なぜ機能がうまくいかないのか誰にでも分かるか、もっと近代的な選択肢を提案できれば(10年前に私が書いた例:P)、私はそれを感謝します。

http://pastebin.com/WM6QhzSK

そして、あなたがアクションでTclの辞書の並べ替えを見たい場合は、下のリンクをチェック:事前に

http://pastebin.com/h3qMT4C2

感謝を!

編集: -私は解決策を導いてくれたchorobaのおかげで!機能は次のとおりです。

sub dict_sort { 
    my @unsorted = @_; 
    my @sorted = 
    map $_->[0], 
    sort { 
     my $i = 0; 
     { 
     my $A = $a->[1][$i]; 
     my $B = $b->[1][$i]; 
     defined($A) || defined($B)  # Stop if both undef 
     and (
      defined($A) <=> defined($B) # Defined wins over undef 
      or (
      $A !~ /\d/ || $B !~ /\d/ # $A or $B is non-integer 
      ? (lc $A cmp lc $B) # ?? Stringy lowercase 
       || ( $A cmp $B) # -> Tie breaker 
      : $A <=> $B    # :: $A and $B are integers 
       or (
       length($A) <=> length($B) # If numeric comparison returns the same, check length to sort by leading zeroes 
      ) 
     ) 
      or ++$i && redo    # tie => next part 
     ); 
     } 
    } 
    map [ $_, [ split /(\d+)/ ] ], @unsorted; 
    return @sorted; 
} 
+0

明確にするために、Tclの辞書ソートは、各単語を唯一の数字と非数字の交互の文字列に分割します。数字シーケンスは数値でソートされます(2つの値が同じ場合、先頭のゼロを処理するために少し魔法を使います)。また、非数字シーケンスは大文字と小文字を区別しないASCIIとしてソートされます。数字で始まるキーと非数字で始まるキーを比較すると、先頭の数字が最初に来ます。 –

+0

誰かが尋ねる前に、これは、ファイル名がどのように分類されるべきなのか、ユーザーが見ているような気がしています。 –

+0

Hm、先行ゼロがここで問題を引き起こしている可能性がありますが、バージョン文字列と絶対パスの両方で同じエラーが発生することはありません。 – Rohaq

答えて

3

バージョン文字列では、コードが異なる動作をしません。リストに9.02 9.2を追加するだけでの順番でとなります。 02が2の後に来るようにしたい場合は、$A == $Bの場合、検査する必要があります。

更新:それは$A <=> $Bor length $A <=> length $Bを追加することを意味します。

+0

それは1.02と1.2を比較しているときに02と2をチェックし、$ A <=> $ Bソートの試行をしたときに同じものとみなすので、順序を変更していません。 これは、$ A <=> $ Bが返されたときに先行する0の現在の数の別のチェックを行うことがより理想的です。 – Rohaq

+0

@Rohaq:はい、その私のポイントでした。 – choroba

+0

ありがとう!数値が一致したときに比較文字列の長さを調べるために検索を拡張しました - 数値比較で同じ値であるが、数値の比較で同じ値であるため、先頭にゼロがなければなりません。 ) 私は自分のコードを編集して作業関数を投げ、あなたのポイントを正しいものとしてマークします。あなたはあなたの答えを編集し、そこに同じような問題を抱えている人を助けるために私の機能をつけることができますか? – Rohaq