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

aaa.txtが例えば以下のようにカンマ区切りのデータだとしますと、

aaa-12,dmy,2014年3月5日,
ccc-22,dmy,2014年3月5日,
ddd-43dmy,,2014年3月4日,
yyy-45,dmy,2014年3月5日,
ddd-43,dmy,2014年3月2日,

※実際は日付は9番目の値になります

これを日付の新しい順にソートしたいのですが、
見よう見まねで以下のようにやった場合、日付順にはなるのですが
同じ日付がありますと上から順番ではなくランダムに処理されてしまい
当初の並びと異なってしまいます。

function cmp($a, $b) {
list(,,,,,,,,,$aa,) = explode(',', $a);
list(,,,,,,,,,$bb,) = explode(',', $b);
if ($aa == $bb) {
return 0;
}
return ($aa < $bb)? 1 : -1;
}

$lines = file('aaa.txt');
usort($lines, "cmp");

最終的には以下のように並べ替えをしたいのですが、

aaa-12,dmy,2014年3月5日,
ccc-22,dmy,2014年3月5日,
yyy-45,dmy,2014年3月5日,
ddd-43dmy,,2014年3月4日,
ddd-43,dmy,2014年3月2日,

日付でソートしますと

ccc-22,dmy,2014年3月5日,
yyy-45,dmy,2014年3月5日,
aaa-12,dmy,2014年3月5日,
ddd-43dmy,,2014年3月4日,
ddd-43,dmy,2014年3月2日,

こんな形で同じ日付の場合、順番が
最初のリストの上から順ではなくバラバラになってしまいます。

どのようにすれば可能になりますでしょうか。

お手数をおかけしますが
具体的なソースをご教授いただけるようですと大変助かります。

何卒よろしくお願い致します。

A 回答 (4件)

もしCSV形式としてそのファイルが有効であれば、fgetcsv関数とfputcsv関数が向いていると思います。



PHP Manual - fgetcsv
http://php.net/manual/ja/function.fgetcsv.php

PHP Manual - fputcsv
http://php.net/manual/ja/function.fputcsv.php

Pentan.info - fgetcsv関数を文字化け対応 setlocaleの文字コード指定
http://pentan.info/php/fgetcsv_char.html

ただ、一度全部の行を1行ずつ配列に読み込ませてはまた1行ずつ保存していくってすごく無駄ですよね。2万件あるなら結構きついと思います。そういうときはシリアル関数の出番です。PHPでは配列をそのままの形で保存したり復元したり出来ます。これであれば10万件程度までは何とかなるでしょう。

PHP Manual - unserialize
http://php.net/manual/ja/function.unserialize.php

PHP Manual - serialize
http://php.net/manual/ja/function.serialize.php

それ以上の世界となると、MySQLなどのデータベースを利用する選択肢に限られてきます。以下の回答を参考にどうぞ。
http://oshiete.goo.ne.jp/qa/8501002.html

こちらの方法ならば、kmeeさんのおっしゃる通り行番号をあらかじめ用意しておき、

SELECT * FROM table_name ORDER BY date_value DESC, index_value ASC

みたいな感じのSQLになると思います。
    • good
    • 0
この回答へのお礼

お忙しい中、ご回答ありがとうございます。

こちらをヒントにして、一度、安定ソートしたデータを
別に保存しておいて、新たに追加されたデータのみを対象にして
安定ソートをかけた後に保存しておいたデータと合算させることにより
無理なく処理が可能になりました。


ありがとうございました。

お礼日時:2014/03/07 23:03

一応補足しておきますね…



ソートの説明についてはkmeeさんの回答が非常に参考になると思います。私の回答では「行番号」に配列のキーをそのまま使用するようにして実現しました。usort関数は値でソート、uksort関数はキーでソートするために使われますが、uksort関数とコールバック関数でのuse句を組み合わせれば、キーと値の両方の情報を同時に使うことが出来ます。

uksort関数の場合、そのままではキーの添え字が維持されるので、振りなおしたい場合はarray_values関数を最後に通す必要があります。
    • good
    • 0

<?php



$data = array(
  array('aaa-12', 'dmy', '2014年3月5日'),
  array('ccc-22', 'dmy', '2014年3月5日'),
  array('ddd-43', 'dmy', '2014年3月4日'),
  array('yyy-45', 'dmy', '2014年3月5日'),
  array('ddd-43', 'dmy', '2014年3月2日'),
);

uksort(
  $data,
  function ($a, $b) use ($data) {
    return
      $data[$a][2] == $data[$b][2] ?
      ($a < $b ? -1 : 1) :
      ($data[$a][2] < $data[$b][2] ? 1 : -1)
    ;
  }
);

$data = array_values($data); // 添え字を振りなおす場合は必要

foreach ($data as $key => $value) {
  $value = implode(', ', $value);
  echo "[{$key}] {$value}\n";
}


ideone.comでの動作確認
http://ideone.com/cBLHu3

この回答への補足

お忙しい中ご回答いただきましてありがとうございます。
完全なご回答をいただきながら以下部分でつまづいてしまっております。

$data = array(
  array('aaa-12', 'dmy', '2014年3月5日'),
  array('ccc-22', 'dmy', '2014年3月5日'),
  array('ddd-43', 'dmy', '2014年3月4日'),
  array('yyy-45', 'dmy', '2014年3月5日'),
  array('ddd-43', 'dmy', '2014年3月2日'),
);


こちらをaaa.txtに置き換えして実行したいのですが、

$datax = @file('aaa.txt');
$data = array($datax);

これでは駄目なのでしょうか。
色々やってはみたいのですが上手くいかず、
知識がなさすぎて申し訳ありません。

自分なりに調べてからどうしてもわからない場合にお願いをさせていただくのですが、
arrayでの例題が多く、txtファイルなどを使った場合、
どのようにこれを置き換えすれば良いのかが全然理解できておりません。

また、aaa.txtは2万行ぐらいありまして、今後も増えていくのですが
あまり増えますとご教授いただいた形ですと厳しいでしょうか。

知識がなさすぎてご迷惑をおかけして申し訳ありません。
もし宜しければご指導いただけますと幸いです。

補足日時:2014/03/06 04:22
    • good
    • 0

ソートには、


同じ「順位」だったときに、元の順番が保存される「安定ソート」

どうなるかわからない「不安定ソート」
があります。

http://php.net/manual/ja/function.usort.php
> 比較結果が等しくなるメンバーが複数存在する場合、 ソート後の配列でのそれらのメンバーの並び順は未定義となります。

と、usortのマニュアルに明記してあります。
つまり、不安定ソートです。(少なくとも、安定ソートとは決めつけることはできない)
# http://www.php.net/manual/ja/array.sorting.php
# によると、usortだけではなく、他のソートも不安定ソートです。


対策は
(1) 用意されたsortではなく、自前で安定ソートのプログラムを用意する
(2) 不安定にならないように工夫する
のどちらかです。

(1)は他言語のものは見つかりますが、PHPで書かれたものは少ないように思います。
(2)は、不安定になるのは同順位のときなのですから、絶対同一順位にならないようにします
例えば
1,aaa-12,dmy,2014年3月5日,
2,ccc-22,dmy,2014年3月5日,
3,yyy-45,dmy,2014年3月5日,
4,ddd-43dmy,,2014年3月4日,
5.ddd-43,dmy,2014年3月2日,
等と「行番号」を付けて、cmpを「日付が同じなら行番で比較」というように変更します。

参考URL:http://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%BC% …
    • good
    • 0
この回答へのお礼

考え方をご教授いただきましてありがとうございます。
自前で作成できるだけのスキルが全然ありませんので
既存のもので少しずつ理解をしていくしかないようです。

番号を最初につけておいて・・と言う所も大変参考になりました。
お忙しい中、ご面倒にも関わらずありがとうございました。

お礼日時:2014/03/06 04:24

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