アマゾネス
ここで書いた物をちょっと修正。
どこが変わったかというと、値段順にソートする部分。
my @nlist = map {$_->[0]} sort {$a->[1] <=> $b->[1]} map { [$_, (split ':', $_)[1]] } @list; # シュウォーツ変換
一般的に書くと、
my @nlist = map {$_->[0]} sort {$a->[1] <=> $b->[1]} map { [$_, (split $sep, $_)[$pos]] } @list; # シュウォーツ変換
$sepが区切り文字、$posがソートキーが何番目にあるかというもの。
これ、実はperlでのXMLパース方法を調べていたときに偶然出てきたんだけど、よく考えると以前本屋で立ち読みしたときに見たことがあった。その時はmapの働きを知らなかったために何をしているのかさっぱりわからなかったけれども今なら分かる。
処理対象となるのは@list。まずはそれをmapを使って一つずつ取り出しながら[元の内容,ソートキー]という無名配列にし、それを元の配列数分繰り返してリストを作る。
次にその無名配列リストを、ソートキーを基準にソートを行う。
ソートが終わったリストを、mapを使って無名配列の最初の要素だけを取り出してリストにして終わり。
いやしかしこんなのよく考えられるもんだ…。
そしてもう一つ。値段を表示するときによくある、3桁毎にカンマを入れていく方法。
最初に見つけたのは、値段の文字列を左右逆転してから、左から三つずつ取り出してカンマを入れていき、最後にまた反転するという方法だった。が、なんかその方法ではおもしろくなかったんでもうちょっと調べてみると今回使っている方法を見つけた。
1 while $price =~ s/(.*\d)(\d\d\d)/$1,$2/;
これがその方法。先頭の1は、まあ0以外だったらなんでもいいかと。一つめの(.*\d)にある.*がミソかと。perlでは、.*みたいに書くと貪欲な探索を行うため、.*は出来るだけ多くの部分にマッチしようとする。
そして後は\dが四つ並んでいるから数値が四つの部分にマッチする。結局一番右の桁から四つの数値にマッチすることになり、それを右の三つと、それ以外の部分に分けられることになる。
たとえば1234567890という数値があったとすれば、1234567が左の括弧、890が右の括弧に入る。そこでカンマで区切るから1234567,890という文字が得られ、また同じ正規表現で探索が行われ、同様に1234と567が括弧に入り置換され1234,567,890という文字になり、.*だから0回でもいいのでこれは1と234に分けられ、1,234,567,890となる。次に正規表現が評価されたときにはマッチしないため、このループは終わる。
ちょっとこれで説明になっているのか不安になってきた…。
まあ分からなければ「こう書けばそうなるんだ」と覚えておくだけでいいかもしれない。