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日,
こんな形で同じ日付の場合、順番が
最初のリストの上から順ではなくバラバラになってしまいます。
どのようにすれば可能になりますでしょうか。
お手数をおかけしますが
具体的なソースをご教授いただけるようですと大変助かります。
何卒よろしくお願い致します。
No.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になると思います。
お忙しい中、ご回答ありがとうございます。
こちらをヒントにして、一度、安定ソートしたデータを
別に保存しておいて、新たに追加されたデータのみを対象にして
安定ソートをかけた後に保存しておいたデータと合算させることにより
無理なく処理が可能になりました。
ありがとうございました。
No.3
- 回答日時:
一応補足しておきますね…
ソートの説明についてはkmeeさんの回答が非常に参考になると思います。私の回答では「行番号」に配列のキーをそのまま使用するようにして実現しました。usort関数は値でソート、uksort関数はキーでソートするために使われますが、uksort関数とコールバック関数でのuse句を組み合わせれば、キーと値の両方の情報を同時に使うことが出来ます。
uksort関数の場合、そのままではキーの添え字が維持されるので、振りなおしたい場合はarray_values関数を最後に通す必要があります。
No.2
- 回答日時:
<?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万行ぐらいありまして、今後も増えていくのですが
あまり増えますとご教授いただいた形ですと厳しいでしょうか。
知識がなさすぎてご迷惑をおかけして申し訳ありません。
もし宜しければご指導いただけますと幸いです。
No.1
- 回答日時:
ソートには、
同じ「順位」だったときに、元の順番が保存される「安定ソート」
と
どうなるかわからない「不安定ソート」
があります。
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% …
考え方をご教授いただきましてありがとうございます。
自前で作成できるだけのスキルが全然ありませんので
既存のもので少しずつ理解をしていくしかないようです。
番号を最初につけておいて・・と言う所も大変参考になりました。
お忙しい中、ご面倒にも関わらずありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
掲示板のあらし対策
-
XML_Serializerで複数のXMLの扱い
-
しりとり 無限ループ?
-
PHP5の外部コマンド実行で、バ...
-
配列の要素(value)に、変数を...
-
csvの内容を行単位で削除したい
-
ftokが動かない?
-
file_existsでファイル名の部分...
-
foreachのなかで次のキーを参照...
-
VBAでcsvファイルもシートもあ...
-
配列をループでたくさん宣言し...
-
stdClass Objectを連想配列のよ...
-
xml取得値を文字列と比較
-
漢字のソートについて
-
2次元配列CSVのソート
-
別ファイルの構造体の値を読み...
-
Eclipseコンテンツアシストでプ...
-
$_SESSIONに二次元配列を使える...
-
String だと「 ByRef引数の型が...
-
CSVデータの行数カウントをした...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
プルダウンメニューにDBの内容...
-
NGワード設定もしくはテキス...
-
日付から順にデータを並び替えたい
-
「ローマ字 -> ひらがな」へPHP...
-
順位を付ける時のスコアの重複...
-
日付、時間の2段階でソート
-
サイト名を取得するPHP
-
要素(文字列)から指定値を検索
-
しりとり 無限ループ?
-
Zend_Form_Element_Hash
-
順位をつけたいです。
-
usortで3つの項目を昇順・降順...
-
年ごとにタイトルを生成し、該...
-
phpとmysqlで「あいまい検索」...
-
PEAR・MDB2のモジュールロード...
-
PHP配列をJavaScriptに渡したい
-
phpでのソートについて
-
Mysqlとphpでソートや更新時の...
-
PHPのプルダウン式のジャンプ設...
-
pukiwikiのユーザ認証の設定で...
おすすめ情報