• ベストアンサー

2007/1/15形式をソートしたい

予約カレンダーを作っています。 ユーザーは不特定の日を予約できます。 CSVファイル 2,1029,2007/1/15,C, 3,1029,2007/1/15,B,checked 4,1029,2007/1/10,D, 5,1029,2007/1/9,C,checked 6,1029,2007/1/16,D, 8,1023,2007/1/17,D 9,1023,2007/1/24,D 10,1023,2007/1/24,C 11,1023,2007/1/10,D ID,会員番号,日付,ステータス,承認 ソートがうまくいかず上記のように並んでいます。 理想としては 9,1023,2007/1/24,D 10,1023,2007/1/24,C 8,1023,2007/1/17,D 11,1023,2007/1/10,D のように日付が新しい方を上にして書き込みたいのです。 2007/1/24のところのソートが上手くいきません。 また、IDの順序も変わると新しいIDをつけるときに困りそうです。 なにかいい方法があったら教えてください。

noname#102619
noname#102619
  • Perl
  • 回答数3
  • ありがとう数1

質問者が選んだベストアンサー

  • ベストアンサー
  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.3

Perlなんでいくらでも小難しく書けるのですが(シュオーツ変換とかで検索してみてください)、 できるだけわかりやすくなるように書いてみました。 #1の方の挙げられたスクリプトはsortのブロックの中で色々処理をしているので、 ソートに伴う比較の回数だけそれを行うことになるので、あまり速度面ではよろしくありません。 こういう場合、ソートのキーとなる部分を取り出して別個に配列に仕立て上げて 処理するのがよくある手段です(これを突き詰めていくとシュオーツ変換になります)。 ソートのキーが複数あり、それらの間で順位が決まっているなら sort のブロックの中で ・優先順位1のキーで比較 (今回の例では日付) ・比較結果が0以外ならそれを返し ・比較結果が0なら(同じ日付)優先順位2のキーで比較しその結果を返す という手順をとればよいです。 use strict; use warnings; my @records = <DATA>; #make sort key my @primekeys; my @subkeys; foreach my $l (@records) { my ($id, $date); ($id, undef, $date, undef) = split q{,}, $l, 4; my ($y, $m, $d) = split q{/}, $date, 3; push @primekeys, ($y*10000 + $m*100 + $d); push @subkeys, $id; } my @sortedkeys = sort {$primekeys[$b] <=> $primekeys[$a] || $subkeys[$a] <=> $subkeys[$b]} 0 .. $#records; my @sortedrecords = @records[@sortedkeys]; print @sortedrecords; __END__ 2,1029,2007/1/15,C, 3,1029,2007/1/15,B,checked 4,1029,2007/1/10,D, 5,1029,2007/1/9,C,checked 6,1029,2007/1/16,D, 8,1023,2007/1/17,D 9,1023,2007/1/24,D 10,1023,2007/1/24,C 11,1023,2007/1/10,D

noname#102619
質問者

お礼

no3さんの方法で試したところうまくいきました。 一発で上手くいくとは思わなかったので驚きです。 ただ、no2さん、no1さん、せっかく回答頂いたのに 試さなくてすみません。 でも、アルゴリズムがわかりました。 みなさんありがとうございました。

その他の回答 (2)

  • guci-ok
  • ベストアンサー率33% (49/146)
回答No.2

色々な書き方があるかもしれませんが、最近私が書いたものです。 ソートブロックの中が込み入っている場合は、結果を求める関数 を別に作って呼び出すと、コードがすっきりします。 #!Perl use File::Slurp; my @data = read_file("A1.csv"); @data = sort { get_date($b) <=> get_date($a) } @data; print @data; sub get_date { my $rec = shift; my $ymd = (split /,/ => $rec)[2]; sprintf '%04d%02d%02d' => (split /\// => $ymd); } __END__

  • okiyoshi
  • ベストアンサー率34% (11/32)
回答No.1

> ソートがうまくいかず とあるので、ソート部分だけだと、 ・各行を項目に分割し、 ・日付を年月日に分割してyyyymmdd形式に統一し、 ・それを降順でソート というところがキモでしょうか・・良い方法かどうかは・・? my @data = <CSV>; # @dataにCSVの全行が有るとして chomp @data; # 必要なら各行末尾の改行コードを除く @data = sort{ my $data_a = join '', map{ sprintf("%02d",$_) } split /\//, (split /,/, $a)[2]; my $data_b = join '', map{ sprintf("%02d",$_) } split /\//, (split /,/, $b)[2]; $data_b cmp $data_a # 日付は数字8桁なのでcmpは<=>でも可 } @data;

関連するQ&A

  • 2006/5/20形式、複数フィールドのソート

    ↓のような感じでデータが入っているとします。 @hogehoge = [ 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 }; これを第1フィールド、第2フィールド(年月日)、第3フィールドの順でソートしたいのですが、具体的にどのようにやればよいのでしょうか? 一番困る点が、2006/05/20形式で保存してあるという 点です。これはやはり分解しないとソートできない のでしょうか?そうなると複雑になります。 http://www.din.or.jp/~ohzaki/perl.htm#SortST は見て試しに作ったのですが、うまくソートされません。 データがそのまま保存されています。 上のURLにある文章を読んだので、特定のフィールドを もとにソートする方法は大体わかりましたが、複数フィー ルドのソートや2006/05/20形式のソートもまじってくる のでわからなくなります。 @hogehoge = [ 1020,2006/5/1,B 1020,2006/5/1,C 1020,2006/5/9,E 1020,2006/5/13,E 1020,2006/5/13,B 1020,2006/5/20,D 1022,2006/5/9,D 1023,2006/5/2,D 1023,2006/5/7,C }; こんな感じでソートさせて保存(書き込み)したいので すが、ご教授よろしくお願いします。

    • ベストアンサー
    • Perl
  • csvファイル内にてソートする方法

    ご協力お願いします。 あるログデータを取得したcsvファイルを作成しました。しかし、データ量も多く見やすいようにソートをかけたいのですが方法がわかりません。csvファイルの中身は以下のようになっています。 ___________________________ | 端末ID | ユーザーID | 日付 | 時間 | ――――――――――――――――――――――――― | ITD002 | 00000001 |2005/08/22| 11:00 | ――――――――――――――――――――――――― | ITD002 | 00000003 |2005/08/22| 21:00 | ――――――――――――――――――――――――― | ITD001 | 00000001 |2005/08/22| 12:00 | ――――――――――――――――――――――――― | ITD001 | 00000002 |2005/08/22| 18:20 | ――――――――――――――――――――――――― 以上のような中身になっています。レコード量は、もっと多いです。このランダムな順番に取得したレコードを 端末ID(昇順)ユーザーID(昇順)日付(降順)時間(降順)でソートする方法をご教授お願いします。

  • select文でソート規則が2つあるとき

    失礼致します。 分かったら教えてください。 今テーブルにid,sort,infoと3つカラムがあり以下のデータが入っています。 id,sort,info (B,1,日本) (B,1,韓国) (A,2,日本) (C,3,ロシア) (C,3,モンゴル) (B,4,中国) このinfoはあまり重要でないので(他2項目が同一の場合の識別子です。)気にしないで下さい。 これを以下のように並べ替えたいです。 (B,1,日本) (B,1,韓国) (B,4,中国) (A,2,日本) (C,3,ロシア) (C,3,モンゴル) 何をしているかというと、 基本的にはsortのascで並べるのですが、同じidを持つものに関しては まとめて取ってきたいのです。 これを考える際、idをorder byの第一要素にするとsortの順序が反映されないし、sortを優先すると同じidのものを連続して取ることができません。 両方を叶えるために何かいい方法は無いでしょうか?

    • ベストアンサー
    • MySQL
  • 多段ソート

    C言語というよりはアルゴリズムの話です。 [名前], [生年月日] の2つのカラムで表される固定長の行データが羅列されたファイルがあります。 また、各カラムを比較して行をソートした場合にどの行が何番目にくるかといったインデックス情報を木構造で保持したファイルがあります。 (このファイルは行データの追加・削除時に更新される) これらのファイルを利用して、生年月日でソートし、かつ日時が同じ場合は名前順にソートした場合の上から10個分だけのデータを取り出したいのですが、効率のよい方法は無いでしょうか? 全データを読み込んでから、バブルソート等の順序を崩さないソートを多重にかけることはなるべく避けたいのです。 そのためにソート済みのインデックス的な役割を持つファイルを用意しているのですが、多段ソート時にどう応用すればよいのかわからなくなってしまいました。 例 日時、名前の順にソートされた上4つ分のデータが欲しい。 【一覧】 [1行目] 10/20, Aさん [2行目] 11/30, Fさん [3行目] 9/10, Cさん [4行目] 11/30, Bさん [5行目] 12/10, Dさん 【生年月日でソートされた インデックス】 9/10, 3行目 10/20, 1行目 11/30, 2行目 11/30, 4行目 12/10, 5行目 【名前でソートされた インデックス】 Aさん, 1行目 Bさん, 4行目 Cさん, 3行目 Dさん, 5行目 Fさん, 2行目 得たい結果 [3行目] 9/10, Cさん [1行目] 10/20, Aさん [4行目] 11/30, Bさん [2行目] 11/30, Fさん

  • VBSでソート&ファイル分割

    VBScriptでCSVファイルを最大5件のレコードになるように ファイル分割しようとしています。 ただし、同じコードが複数のファイルに分かれないようにしたいです。 入力するCSVファイル(test_in.csv)は以下のような形式です。 (実際のファイルに項目行はありません) 連番,コード,フラグ,日付 01,0001,A,20091001 02,0002,A,20091001 03,0003,A,20091002 04,0001,U,20091003 05,0003,D,20091003 06,0004,A,20091003 07,0005,A,20091003 08,0001,D,20091005 09,0006,A,20091003 10,0006,A,20091003 ※入力ファイルに同じコードのレコードが5件を超えることはありません) 上記の入力ファイルの場合は以下の3つのファイルに分割することになります。 【test_out_001.csv】 01,0001,A,20091001 04,0001,U,20091003 08,0001,D,20091005 02,0002,A,20091001 【test_out_002.csv】 03,0003,A,20091002 05,0003,D,20091003 06,0004,A,20091003 07,0005,A,20091003 【test_out_003.csv】 09,0006,A,20091003 10,0006,A,20091003 ※コード"0003"のレコードは2件あるので、test_out_001.csvには出力せず、  test_out_002.csvに出力します。  コード"0006"についても同様でtest_out_003.csvに出力します。 処理の手順としては 入力ファイルのデータをコードでソートし、 1ファイルに5件を超えないように追加していくのかと思いますが、 ソートと5件制限はどのように記述すればよいでしょうか?

  • フォルダとファイルを区別せずソートする方法

    Windows7でファイルの整理をしようと思ったのですが、日付順でソートすると フォルダとファイルが別々にソートされてしまいます。 ネットで検索して同様の質問を見つけたのですが、特定のフォルダの記載方法がよくわからず うまく試せませんでした。 デフォルトのC:Users¥○○>では多分試せたと思います。 http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1235761152 コマンドプロンプトでの特定のフォルダの記載方法もしくは フォルダとファイルを一緒にソートする方法はないでしょうか?

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

    2次元ハッシュのソートをしたいです。 ハッシュは2つのキーを使用していて、 1つ目のキーは文字列、2つ目のキーは数字(0からの連番)です。 ハッシュの中身は文字列が入っています。 これを次のような表に見立てて、特定の列でソートしたいのです。 hash['a']['0'], hash['a']['1'], ..., hash['a']['50'], hash['q']['0'], hash['q']['1'], ..., hash['q']['50'], hash['c']['0'], hash['c']['1'], ..., hash['c']['50'], ... hash['d']['0'], hash['d']['1'], ..., hash['d']['50'], 例えば 6列目の値によってソートするということです。 以下のようにソートしようとしましたが、うまくいきません。 my @sorthash = sort { $a->[6] <=> $b->[6] } @hash; 何かヒントがあれば教えてください。

    • ベストアンサー
    • Perl
  • EXCEL2003で日付をソートしたい

    エクセル2003で出納帳を作成しています。 日付をソート(若い順)するにはどうしたらよいでしょうか?? A列 6/1 6/2 6/3 6/1 6/2 これを A列 6/1 6/1 6/2 6/2 6/3 という感じにしたいです。 B列以降C,D,E~には、文字列、関数、数値等が入力されており、それも同時に動かしたいのですが… よろしくお願いします。

  • 配列のソート

    下記のような形でデータを取得し結果を配列に格納し、 降順にソートしたいのですが、いい方法が見つかりません。いい方法はあるでしょうか。よろしくお願いします。 テーブル構造(test) ID|name |point|area| ==================== 1 |Aさん|56 | A | 2 |Bさん|12 | B | 3 |Cさん|24 | B | 4 |Dさん|34 | B | $sql = "select * from test"; $result = mysql_query($strSQL); while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) { ここで配列に格納 } 配列への格納方法と、pointの降順にソートする 方法が知りたいです。 最終的に、Aさん、Dさん、Cさん、Bさんと なるようにしたいです。

    • ベストアンサー
    • PHP
  • ACCESS テーブル内の特定の文字の置換

    お世話になっております。 Access2007+VBAについてになります。 フィールド内の特定の文字を置き換えたいのですが、どのようしたら良いでしょうか。 例えば・・・ テーブル_Aと、テーブルBがあります。 テーブルAには、フィールドCに抽出したいデータのIDが入っています。 テーブルBには、フィールドDに置換えたい日付が入っています。 フィールドDの日付は、『日付は2015-12-22です。』となっており、 フィールドCのIDと、テーブルBにあるフィールドEというIDがマッチしたフィールドDの日付を、『日付は、2015-12-23です。』に置き換えたいと思っています。 IDは、両方ともに、オートナンバー型ではありません。 色々試してみたのですが、全く分かりません。 是非、ご教授をお願い致します。

専門家に質問してみよう