- ベストアンサー
2006/5/20形式、複数フィールドのソート
- 質問文章で提供されたデータを第1フィールド、第2フィールド(年月日)、第3フィールドの順でソートする方法について教えてください。
- 質問文章で述べられているように、2006/05/20形式で保存されているデータをソートするには、年月日を分解する必要があります。
- 2006/5/20形式のソートを行う際には、特定のフィールドをもとにソートする方法を使用し、複数フィールドのソートも組み合わせて実行する必要があります。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
えーと、 #1のスクリプトの末尾に for my $item (@sorted_table) { printf "ID1:%d, Date:%s, ID2:%s\n", $item->[0], $item->[1], $item->[2]; } というのを追加して結果を以下のように出力してみましたが、 ID1:1020, Date:2006/5/1, ID2:B ID1:1020, Date:2006/5/1, ID2:C ID1:1020, Date:2006/5/9, ID2:E ID1:1020, Date:2006/5/13, ID2:B ID1:1020, Date:2006/5/13, ID2:E ID1:1020, Date:2006/5/20, ID2:D ID1:1022, Date:2006/5/9, ID2:D ID1:1023, Date:2006/5/2, ID2:D ID1:1023, Date:2006/5/7, ID2:C ID1が同じときには日付を使ってソートしていて、きちんと 5/9が5/13や5/20よりも前に来ているのですが、どのようなデータで どうなったのでしょうか? [1][2]のような書き方は、リスト(配列)の要素にリストが来ているときの 入れ子になったほうのリストの要素へアクセスするときに使います。 詳しくは参考URLをどうぞ。
その他の回答 (2)
- sakusaker7
- ベストアンサー率62% (800/1280)
すみません。バグってました。 $a->[1][2] <=> $b->[1][1] # 第2フィールドで比較 日 は $a->[1][2] <=> $b->[1][2] # 第2フィールドで比較 日 の間違いです($bの後のカッコの添え字が違う)。 比較が間違っているのでソート結果もおかしくなってますね。 それと、 (split(/\,/,$a))[1] cmp (split(/\,/,$b))[1] の件ですが、これだとフィールドを文字列として比較してしまうので、 '9' が '12' より大きくなってしまいます。'09'だと正しく並ぶのは 文字列比較しても'09'は'12'より小さくなるからです。cmpは文字列として 比較、<=>は数値として比較を行う演算子ですので選択するときは気をつけてください。
- sakusaker7
- ベストアンサー率62% (800/1280)
@hogehoge が ( [1020, '2006/5/1', 'B'], [1020, '2006/5/1', 'C'], ... ); というフォーマットの間違いであるなら、以下のようにしてできます。 日付が05/01のようになっていなかったので、分割しています。 もし0が補完されているなら、分割せずに文字列比較で済ませることもできます。 use strict; use warnings; # use Data::Dumper; デバッグ用 my @table = ( [1020, '2006/5/13', 'B'], [1020, '2006/5/1', 'B'], [1020, '2006/5/1', 'C'], [1020, '2006/5/13', 'E'], [1023, '2006/5/2', 'D'], [1020, '2006/5/20', 'D'], [1023, '2006/5/7', 'C'], [1020, '2006/5/9', 'E'], [1022, '2006/5/9', 'D'] ); my @tmp = map {[$_, [split '/', $_->[1]]] } @table; my @sorted_tmp = sort { $a->[0][0] <=> $b->[0][0] # 第1フィールドで比較 or # 第1フィールドが同じなら $a->[1][0] <=> $b->[1][0] # 第2フィールドで比較 年 or $a->[1][1] <=> $b->[1][1] # 第2フィールドで比較 月 or $a->[1][2] <=> $b->[1][1] # 第2フィールドで比較 日 or # 第2フィールドも同じなら $a->[0][2] cmp $b->[0][2] # 第3フィールドで比較 } @tmp; my @sorted_table = map {$_->[0]} @sorted_tmp; # print Dumper(@sorted_table); デバッグ: 結果の確認 以上の手順で @sorted_tableにソートした結果が入ります。 map→sort→mapは一行にまとめてもよいのですが、そうすると さらにわかりにくくなると思うので分割しました。 興味があればシュオーツ変換(Schwartzian transform)で検索してみてください。
お礼
お礼おそくなりました。回答ありがとうございました。 いま自分で検証中なのですが、ひとつ上手くできません。 まず、↓のソートはできました @txt = sort { $a->[0] <=> $b->[0] or $a->[2] cmp $b->[2] } @txt; 第1フィールドと第3フィールドのソートは できました。 ↓の第2フィールドのソートができません。 $a->[1][0] <=> $b->[1][0] # 第2フィールドで比較 年 or $a->[1][1] <=> $b->[1][1] # 第2フィールドで比較 月 or $a->[1][2] <=> $b->[1][1] # 第2フィールドで比較 日 ためしに単純に (split(/\,/,$a))[1] cmp (split(/\,/,$b))[1] こんな感じのソートなら近いものができました。 ただ、 1999/2/12 1999/2/13 1999/2/15 1999/2/15 1999/2/8 1999/2/9 のようになってしまいます。つまり、一桁の数字が 後方に移動されます。 数値形式が 1999/02/08 の形式ならばちゃんとできるみたいです。 でも、1999/2/9形式でできればそれで実行させたい です。 それにはsakusaker7さんに教わった方法になるの でしょうが、第2フィールドのみ完全に上手く比較 されていないようなのです。 もしまたなにかヒントがあれば教えてください。
お礼
早速の訂正ありがとうございます。 そちらのバグには即座に気づいたので訂正し、トライしてみましたが第2フィールドがソートされません。 [1][2] の書き方はWEB、本にも載っていなく、現在調べておりますが、そういう書き方があるのですね。 また、本屋行って調べてみますが、いいヒントがあればまた教えてください。