アプリ版:「スタンプのみでお礼する」機能のリリースについて

予約カレンダーを作っています。
ユーザーは不特定の日を予約できます。

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をつけるときに困りそうです。

なにかいい方法があったら教えてください。

A 回答 (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
    • good
    • 0
この回答へのお礼

no3さんの方法で試したところうまくいきました。

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

みなさんありがとうございました。

お礼日時:2007/02/09 03:31

色々な書き方があるかもしれませんが、最近私が書いたものです。


ソートブロックの中が込み入っている場合は、結果を求める関数
を別に作って呼び出すと、コードがすっきりします。

#!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__
    • good
    • 0

> ソートがうまくいかず


とあるので、ソート部分だけだと、
・各行を項目に分割し、
・日付を年月日に分割して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;
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!