• ベストアンサー

2次元ハッシュ または 2次元配列をソートしたい

taknak08の回答

  • taknak08
  • ベストアンサー率50% (8/16)
回答No.2

Wernerさんが指摘されているとおり、Perlの文法に誤りがあるようですので、まずは入門書から紐解かれるとよいと思います。 (PHPご出身でしょうか? PHPとPerlはどちらも「$」や「[...]」を用いており、ぱっと見は似てはいますが、実際はかなり異なる言語です。) 「1つ目のキーは文字列、2つ目のキーは数字(0からの連番)です。  ハッシュの中身は文字列が入っています。」 をそのままPerlで書くと、下記のようになるでしょうか。 my %hash = ( 'a' => ['aiueo', 'kakiku', 'sasisu'], 'q' => ['zzzzz', 'yyyyyy', 'xxxxxx'], 'd' => ['a0123', 'b98765', 'c77777'], ); Perlでは、ハッシュに順番はありませんので、「%hashの中身を直接並び替える」ということはできません。 しかし「$hash{'...'}[1]='xxx' のように2列目(←1列目を[0]と数えています)の値(=この場合は'xxx')の大小で並び替えた%hashのキー一覧(=この場合は'...'の一覧リスト)を取り出す」ということはできます。 一度下記のコードをお試しください。 use strict; my %hash = ( 'a' => ['aiueo', 'kakiku', 'sasisu'], 'q' => ['zzzzz', 'yyyyyy', 'xxxxxx'], 'd' => ['a0123', 'b98765', 'c77777'], ); print "hash{'q'}[1] is '", $hash{'q'}[1], "'.\n\n"; # yyyyy print "Sorted by the string of 2nd column:\n"; my @sorted_key = sort { $hash{$a}[1] cmp $hash{$b}[1] } keys %hash; for my $sorted_key (@sorted_key) { print "hash{'", $sorted_key, "'}: "; for (my $i = 0; $i < 3; ++$i) { print "[", $hash{$sorted_key}[$i], "]"; } print "\n"; }

palayo
質問者

お礼

最初の質問で、ハッシュと書きながら配列表記にしてしまったのは 混乱を招いたようで、失礼しました。 ただ、perl の文法の誤りはどこにあるのか分からないので、教えていただけないでしょうか。 $i が0,1,2,3,... のような整数値の場合にも、$hash{$i} のようなハッシュって使えますよね? ですから、前のソースで書いている表記 $csv_data{$name}{$i} のような 書き方も文法上の誤りはないと思うのですが・・・。 実際のところ、ソート以外の部分はちゃんと動作してましたし。 2変数のハッシュとして書けば $csv_data{$name}{$i} となり、 2次元のハッシュ配列(なんていうの?)として書けば、 taknak08様の指摘するような $csv_data{$name}[$i] となるだけの違いかと・・・。 確かに、今回の条件では taknak08様の方法の方が適切ではありますが、 文法上はどちらも正しいのでは?? 私の認識違いでしたら、教えてください。 さて、実際のところは、配列を格納したハッシュにするのが一番適切かと思い、修正してみました。 補足のソースで一応動作しています。 ただ、ソートするとデータが1件(1行)だけ失われます。 元のcsvでカラム名に使われていた行なのですが・・・。 ソートせずに出力すると、ちゃんと出力されます。 (当然、先頭ではない行に出力されてしまいますが) なんとか修正したいのですが、原因が分かりません。 何か分かれば教えていただけないでしょうか?

palayo
質問者

補足

open(DATA, '<', $csv_file) or die "csv file does not exist."; while (my $line = <DATA>) { $line .= <DATA> while ($line =~ tr/"// % 2 and !eof(DATA)); $line =~ s/(?:\x0D\x0A|[\x0D\x0A])?$/,/; my @values = map {/^"(.*)"$/s ? scalar($_ = $1, s/""/"/g, $_) : $_} ($line =~ /("[^"]*(?:""[^"]*)*"|[^,]*),/g); @{$content{$values[6]}} = @values; } close(DATA); # ソートしない場合には、カラム名の行も出力されますが、 # ソートするとカラム名の行が出力されません。 #my @sorted_keys = keys( %content ); my @sorted_keys = sort { $a cmp $b } keys( %content ); open(OUT, '>'. "$new_csv_file"); for (my $i = 0; $i < $#sorted_keys; $i++) { my $line = join ',', map {(s/"/""/g or /[\r\n,]/) ? qq("$_") : $_} @{$content{$sorted_keys[$i]}}; print OUT $line,"\n"; } close(OUT);

関連するQ&A

  • 二次元ハッシュ

    hash[3][3]=9; 上記のように、2次元のハッシュを使いたいです。 1次元のハッシュは hash1= new Object(); と定義して、 hash['key']=1; などとアクセスすればよいのは調べたのですが、2次元の場合はどのように定義するのか教えてください。 ※オーサリングツール『はParaFla!』ActioScitptは1.0相当です。 よろしくお願いいたします。

    • ベストアンサー
    • Flash
  • ハッシュのハッシュのソート

    rubyでハッシュのソート方法についてはいくつか情報のサイトを見つけられました。 ですが今やりたいのは、ハッシュのハッシュのソートなのですが、うまいやり方がわかりませんでした。 具体的には、 h1 = {"user1"=>{"a"=>10, "b"=>20, "c"=>30"}, "user2"=>{"d"=>5, "e"=>8}, "user3"=>{"f"=>10, "g"=>5, "h"=>10} } というようなハッシュのハッシュを想定しています。ユーザごとに案件ごとの必要工数(時間)をハッシュとして持たせ、全工数が多いユーザ順にソートしたいのです。 上記の場合だと、 {"user1"=>{"a"=>10, "b"=>20, "c"=>30"}, "user3"=>{"f"=>10, "g"=>5, "h"=>10}, "user2"=>{"d"=>5, "e"=>8} } というようにソートしたいのですが、何かやり方がありましたらご教授いただけますでしょうか。

    • ベストアンサー
    • Ruby
  • 二次元ハッシュの引き出し方について

    2次元のハッシュをObjectを用いて作り、以下の様に第一キー固定で第二キーを取り出したいです。 ----------------------------------------------------------- hash = new Object; hash[3] = new Object; hash[3][1] = 3; hash[3][2] = 6; hash[3][3] = 9; for (key in hash[3]){  _root.debug+=key; } ----------------------------------------------------------- 上記は上手く動かないので、以下の様に修正しました。 ----------------------------------------------------------- hash = new Object; hash[3] = new Object; hash[3][1] = 3; hash[3][2] = 6; hash[3][3] = 9; tmp=hash[3]; for (key in tmp){  _root.debug+=key; } ----------------------------------------------------------- いったんtmpに代入する事で期待通りの結果が得られましたが、スッキリしません。 Perl等の他言語では、「無名ハッシュ」という概念を表記化することができるので、Actionscriptでも良い表記方法がありましたら教えてください。 ※オーサリングルールはParaFla! ActionSctiptは1.0相応です。

  • Ruby 2次元のハッシュ

    Rubyで2次元のハッシュを扱いたいです。 perlで書くと以下のような感じです。(最近perlに疎遠なので自信無いですが^^;) hash{$key1}{$key2}=$value; foreach $key1 (keys %hash){ foreach $key2 (keys %{$hash{$key1}}){ print "$hash{$key1}{$key2}\n"; } } Rubyだとどんな感じになりますか?

  • 二次元配列のハッシュ版の記述方法?

    二次元配列のハッシュ版を実現させたいのですが、 以下の記述で正しいでしょうか? 構文に疎いので教えてください。 #!/usr/bin/perl %HASH_TEST = ( 'あ'=>{'A'=>'1', 'B'=>'2', 'C'=>'3'}, 'い'=>{'A'=>'4', 'B'=>'5', 'C'=>'6'}, ); print $HASH_TEST{'い'}{'B'}; #=> 5が表示されます。 exit; __END__

    • ベストアンサー
    • Perl
  • 【javascript】ハッシュのキーをソートして取り出したい

    ハッシュのキーをソートして取り出したいです。 perlで表現すると、以下の様なかんじです。 foreach $key (sort keys %hash) { ... } そこで、prototype.jsを使って以下の様に書いてみました。 <html> <head> <script type="text/javascript" src="prototype.js"></script> </head> <body > <script > var table = {c:'C', b:'B', a:'A'}; $H(table).keys().sort().each(function(key){ alert(key + ' ' + table[key]); }); </script> </body> </html> 他に良い方法ありましたら、教えてください。

  • 多次元配列のソート

    過去に同様の質問があったのですが、未回答でしたので質問させていただきます。 多次元配列のうちの一つの列の値でソートし、その他の列にも結果を連動させたいのですが方法が分かりません。 たとえば、a[n][m]という配列で a[0][0]=C a[0][1]=う         a[0][0]=A a[0][1]=あ a[1][0]=A a[1][1]=あ   →    a[1][0]=B a[1][1]=い a[2][0]=B a[2][1]=い         a[2][0]=C a[2][1]=う というように、n列でソートしm列でもその結果で並べ替えたいです。 恐らくComparatorインタフェースを使用すると可能かと思うのですが、方法を教えて頂けないでしょうか。

    • ベストアンサー
    • Java
  • 静的ハッシュの配列のキーに対応する値の数の多さ順で表示させたい

    ハッシュのキーに対応する値の数の多さ順で表示させたいと考え、下記の所まで試行錯誤しておりますが、どうにも思ったようにソートできずにおります。 #!/usr/bin/perl use strict; my(%a, $i, $j ,$allarray ,@keys ,@keys2 ,%hash ,%files ,$a_mumei_ref ,$key ,$value ,@value ,$x ,$files); # ハッシュの配列を静的に作る %a = ( '0' => [ qw(0) ], '1' => [ qw(1 1) ], '3' => [ qw(3 3 3) ], '7' => [ qw(7 7 7) ], '2' => [ qw(2) ], '4' => [ qw() ], '5' => [ qw() ], '6' => [ qw() ], '8' => [ qw(8 8) ], '9' => [ qw(9) ], ); @keys = sort { $hash{$b} <=> $hash{$a} || length($b) <=> length($a) || $a cmp $b } keys %a; #ハッシュのキーを数字順で表示 foreach (@keys){ print $_ ."\n"; } # 静的に作ったハッシュの配列を取り出してみる foreach $i (sort keys %a) { for ($j = 0; $j <= scalar(@{$a{$i}})-1; $j++) { print '$a{'. $i. '}['. $j. ']='. $a{$i}[$j]. ' '; } $allarray=scalar(@{$a{$i}})-1; print "No$i:kosuu:$allarray"; print "\n"; #配列の値の個数を調べその配列を作成 my($a_mumei) = $allarray; $a_mumei_ref = \$a_mumei; $files{"$i"}=($i,$a_mumei_ref); } #each関数で%filesの中身を表示 while ( ( $key , $value ) = each %files ){ print "key:$key value:$$value\n" ; } #試行錯誤 foreach $x (sort { $files{$b} <=> $files{$a} } keys %files){ print "$x => $files->{$x}\n"; } @keys2 = sort {$hash{$a} <=> $hash{$b}} keys %files; #@keys2 = sort { $hash{$b} <=> $hash{$a} || length($b) <=> length($a) || $a cmp $b } keys %files; #@keys2 = sort { $hash{$a} cmp $hash{$b} } keys %files; print "@keys2\n"; print "\n"; __END__; 私のイメージしておりますのは、ソートした結果がハッシュのキーに対応する値の数の多さ順で下記のように表示させたいのですが、 どのようにすれば可能でございますか、ご教授願えませんでしょうか key:3 value:2・・・この場合valueは配列の個数 key:7 value:2 key:8 value:1 key:1 value:1 key:9 value:0 key:2 value:0 key:0 value:0 key:6 value:-1 key:4 value:-1 key:5 value:-1

    • ベストアンサー
    • Perl
  • ハッシュのハッシュを値とキーでソートする方法

    %array = ( 'A' => {   'a' => 7,   'b' => 3,   'c' => 9,   'd' => 1, }, 'B' => {   'a' => 3,   'b' => 8,   'c' => 3, },); のようなハッシュがあったとして、値の降順、1つ目のキー昇順、2つ目のキー昇順でソートし、下のような形で出力したいのですが、どのようにすればよいのでしょうか。 A  c  9 B  b  8 A  a  7 A  b  3 B  a  3 B  c  3 A  d  1

    • ベストアンサー
    • Perl
  • 動的ハッシュを作って取り出したいのですが・・・

    お世話になります。 フォームから送られてくるデータを動的に作ったハッシュで参照出来るように取り組んでるんですが、思ったように出来ず思い悩んでおります。 どうすれば、意図した形でデータを取り出すことが出来ますでしょうか my %FORM = ( 'd01' => 'あ', 'd02' => 'い', 'd03' => 'う', 'd04' => 'え', 'd05' => 'お', 'd06' => 'か', 'd07' => 'き', 'd08' => 'く', 'd09' => 'け', 'd10' => 'こ', ); for(sort { $FORM{$a} cmp $FORM{$b} } keys %FORM){ print "$_ = $FORM{$_} \n"; } $list="d01,d02,d03,d04,d05,d06,d07,d08,d09,d10,"; $i=-1; foreach (split/,/,$list){ $i++; $hash{$_}=$i; } for(sort { $hash{$a} <=> $hash{$b} } keys %hash){ print "$_ = $hash{$_} \n"; $view = ${"FORM$_"}; print "$view\n"; }; 最後のprint "$view\n";箇所で、 $list="d01,d02..." を split/,/,$list したので、 $FORM{d01} $FORM{d02} となるようにして、 「あ い う え お」と取り出したいのです。 ご教授のほど、よろしくお願い致します。

    • ベストアンサー
    • Perl