ハッシュ内配列内の任意のフィールドの値でハッシュをソートする
久しぶりにperl書いた。
{なのか[なのか(なのかわからん。
あとおもわず
@array.pop
とか書いてしまう。ruby病。行末の;もよく飛ばす。
で、題名の配列をvalueに持つハッシュを配列のなかの任意のフィールドの値でソートしたいなぁ、という件。
この辺訳わかんなくなるのでメモ。
#ハッシュの宣言 my %hash; #$hash['hoge'] = [1とか数字な「評価」,'意味string']な構造 #検索はハッシュのキーでしたいし、評価は配列内の評価で行いたい。 #で、データ上の本当の意味値は'意味string' #もうこの時点でなんだかアホーなデータ構造ですけど。 #配列の値へのアクセス。いろんな方法あるけど見やすいのは #'意味string'を取得したい my $hash{'hoge'}->[1]; #'->'がやっぱり見やすい。 #ハッシュの'意味string'を値順に出力したい #方法1.key配列を持ってきてforeachで回す my @keys = sort {$hash{$a}->[0] <=> $hash{$b}->[0]} keys %hash; foreach(@keys){print $hash{$_}->[1];} #方法2.出力するだけならもうmapでいいじゃん print map{$_->[1]} sort{$a->[0] <=> $b->[0]} values %hash; #mapとソートを使いこなせばかなり簡潔に書けるけど読みやすいかどうかとは別問題。 #正直きもい。でも考えてて気持ちいい。 @myvalues = values(%hash); #valueの配列を格納(配列の配列になってる) @mysorted = sort{$a->[0] <=> $b->[1]} @myvalues; #配列(親)の各要素である配列(子)の2個目のフィールド値をつかって配列(親)をソート @maymapped = map{$_->[1]} @mysorted;#出力する際に必要な配列(子)の2番目のフィールドの配列を作成。 #参照値でもっとウマウマにできるのだろうけどキモすぎて書いても顰蹙を買うこと必至でしょう。
追記
perlではハッシュの中身の配列とか、配列の中身のハッシュとかは無名配列/ハッシュになるのね。
要するに参照値。なのでデリファしたりとかキモイ。混乱する。っていうかわかんない。
$arrayr =[1,1,1,]
print $arrayr->[1],"\n";
とかって事か。なぜこんらんしているのだろう?
rubyなら!ってことだろう。
#hash内arrayとか ha = { 'hoge' => [1,"1hfdsafdsasa"], 'h3oge' => [3,"3hfdsafdsasa"], 'ho3ge' => [22,"22hfdsafdsasa"], 'h3oge' => [64,"64hfdsafdsasa"], 'hog33e' => [13,"13hfdsafdsasa"], } #hash内配列へのアクセス p ha['hoge'][1] #内部はしらないがこの方法でOK。 #memo:ha{'hoge'}は受けつけないし、['hoge']で統一は楽。 # arr = (2,3,3,3)も受け付けない。 #ソート #まずどうでも良いことだけど実はハッシュ格納時に緩くソートされてる has = { '1' => 'one', '4' => 'four', '3' => 'three', '2' => 'two', } p has #=>{"1"=>"one", "2"=>"two", "3"=>"three", "4"=>"four"} #で本題。さっきのhaを配列内のインデクス0の値でソートしましょうそうしましょう。 #方法 #1.できるだけperlの時と同じに。ソートされたvalueの配列をmapする sortedValueArray = \ ha.values.sort{|a,b| a[0] <=> b[0]}.map{|$_| $_[1]} p sortedValueArray #memo:行の最初で早々にハッシュじゃなくなってる! #2.sortされたkeyの配列を持ってきてアクセスする sortedKeyArray = ha.keys.sort_by{|k| ha[k][1].to_i} p sortedKeyArray #この配列を使ってアクセス sortedKeyArray.each{|k| p ha[k]} #memo:なんだか一次配列とかなぁ。。。後からみて把握しづらいなぁ。 #3.to_aなやり方↑はどう見ても迂遠でしょ ref:逆引きRuby p ha.to_a.sort_by{|a| a[1][0].to_i }.map{ |$_| $_[1][1] } #memo:1.とほとんど同じだけど大事なことは # mapの直前では未だデータ構造のこってる、という安心感。 # でもvalueをソートしたいんだ!ッてときは1の方法が読みやすいのかも
感想
rubyのアクセス周りが感覚的で楽です。
やりたいことしか考えないで済む感じがする、個人的な感覚だけど。
関係ないけどrubyのsort_by
perlにもあった気がするけど調べる気はない。effectiveperlあたりにのってた気がする
逆引きRubyのsort
http://www.namaraii.com/rubytips/?cmd=view&p=%C7%DB%CE%F3&key=%A5%BD%A1%BC%A5%C8#l13
にsortがあるけど今回はsort_byをつかてみた。
初心者が逆引きRubyを編集する勇気はないの!
でも書いたら僕が楽なんだろうなぁ。覚えとくのめんどい。忘れときたいしなぁ。
条件式を指定したソート2
sort_byメソッドではブロックの返値を使ってソートする。sortメソッドに比べて各要素の評価回数が1回ずつなので計算回数が少なくて済む。
a = [10,1,5] p a.sort_by{|a| a.to_i}