2017-03-01 6 views
3

配列の要素のサイズで配列をソートしようとしています。アイテムは、パターンx/y[.../z]に従っています。アイテムの数量に応じてソートします。例えば。 1/2には、/で分割した後に2つの項目があり、12/365/85には3つあります。私はこのような一見単​​純なスニペットで間違っていることを理解しているようには見えません。分割のサイズで配列を並べ替える

#!/usr/bin/perl 
use strict; 
use warnings; 

use Data::Dumper; 

my @dummy_arr = ['12345/3/365/45/12', '1/2', '3/2', '1/2/3', '2/3/4']; 
@dummy_arr = sort { scalar (split /\//, $a) < scalar (split /\//, $b) } @dummy_arr; 

print Dumper(\@dummy_arr); 

出力:

$VAR1 = [ 
      [ 
      '12345/3/365/45/12', 
      '1/2', 
      '3/2', 
      '1/2/3', 
      '2/3/4' 
      ] 

     ]; 

予想される出力:

$VAR1 = [ 
      '1/2', 
      '3/2', 
      '1/2/3', 
      '2/3/4', 
      '12345/3/365/45/12' 
     ]; 

答えて

11

あなたはいくつかのことを混同しています。

@dummy_arrに配列参照を挿入します。また、目に見えるのです、あなたのDumper出力で

my @dummy_arr = ([ '12345/3/365/45/12', '1/2', '3/2', '1/2/3', '2/3/4' ]); 

my @dummy_arr = [ '12345/3/365/45/12', '1/2', '3/2', '1/2/3', '2/3/4' ]; 

これはに等しいです。

$VAR1 = [     # <-- because of the ref \@dummy_arr you pass to Dumper 
      [     # <-- first elem is already an array ref 
      '12345/3/365/45/12', 
      '1/2', 
      '3/2', 
      '1/2/3', 
      '2/3/4' 
      ] 
     ]; 

あなたがsort { ... } @dummy_arrをしたときに、sortに渡された一つの値だけがありました。 sortはスマートなので、$aしかない場合はソートするものがないため、スキップしますが、$bはありません。これは、ラムダsort{ warn $a; scalar ... }を入れると明らかになります。警告はないので、決して呼び出されません。

しかし、とにかくソートされていません。 sort lambdaは、-1,0または1に似た何かを返す必要があります。

SUBNAMEを指定した場合、それは 、リストの要素が順序付けされる方法に に応じて、等しい、未満又は0より大きい整数を返すことサブルーチンの名前を与えます。

しかし、あなたは唯一の1または0返し<を、使用しています。 <=> for numerical comparisonを使用する必要があります。最後に

my @dummy_arr = ('12345/3/365/45/12', '1/2', '3/2', '1/2/3', '2/3/4'); 
@dummy_arr = sort { scalar(split /\//, $a) <=> scalar(split /\//, $b) } 
    @dummy_arr; 

print Dumper(\@dummy_arr); 

__END__ 
$VAR1 = [ 
      '1/2', 
      '3/2', 
      '1/2/3', 
      '2/3/4', 
      '12345/3/365/45/12' 
     ]; 

、分割は多くの要素が配列に存在する場合、あなたはこのためにa Schwartzian Transformを使用する場合がありますたくさんを繰り返す必要がある高価な操作ですので。

my @dummy_arr = ('12345/3/365/45/12', '1/2', '3/2', '1/2/3', '2/3/4'); 
@dummy_arr = 
    map { $_->[0] } 
    sort { $a->[1] <=> $b->[1] } 
    map { [ $_, scalar split(qr{/}, $_) ] } @dummy_arr; 

これは同じ出力を生成しますが、CPUのメモリと交換されるため、高速です。

+1

さらに正確に言えば、ソートラムダは< 0, 0,or >を返さなければなりません。したがって、もう一つのアプローチは '<'を '-'に置き換えることです。 – Flimzy

+0

@Flimzyあなたは正しいです。一定。 – simbabque

+1

D'oh!私はさまざまな言語で一日中作業しているため、異なる言語のデータ型間の構文上の違いを忘れてしまいます。 Schwartzian Transformの+1も非常に興味深い! –