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で質問しましょう!
似たような質問が見つかりました
- 兄弟・姉妹 ① 2014年3月生まれの8歳3年生 2015年4月生まれの7歳1年生 年齢は1歳差だけど学年は2歳 2 2023/03/04 16:39
- 兄弟・姉妹 ① 2014年3月生まれ8歳3年生 2015年4月生まれ7歳1年生 学年は2歳差だけど年齢は1歳差 1 2023/02/24 19:50
- 子供・未成年 ① 2014年1月生まれの8歳3年生 2015年4月生まれの7歳1年生 ② 2014年4月生まれの8 1 2022/10/15 10:43
- C言語・C++・C# C言語のマクローリン展開ローラン展開のコードについて 3 2022/12/15 14:45
- MySQL 【MySQL】本当に困っています。詳しい方、ご教授よろしくお願いします。 1 2023/06/03 14:18
- その他(スポーツ) 北海道コンサドーレ札幌の話 1 2022/10/25 21:45
- Excel(エクセル) エクセルの数式で教えてください。 2 2023/01/10 09:15
- その他(スポーツ) 札幌ドームの話 1 2022/06/14 06:09
- アニメ ドラえもんで 初代 富田耕生(1936年2月4日生まれ) 1973年4月1日〜1973年6月24日 2 2023/02/21 18:36
- 就職・退職 有給休暇日数について教えてください…! 4月1日に入社し、次の年の4月14日付で退職したのですが有給 6 2023/08/26 04:36
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
phpのin_array()でわからない事...
-
スカラーのベクトル微分
-
PHPでの簡易ビンゴゲームでの疑...
-
PHPでテキストファイルの一部を...
-
別ファイルの構造体の値を読み...
-
PHPで連想配列のプルダウンメニ...
-
配列を分解したいのですが
-
バイナリファイルの内容を、そ...
-
C言語で全角文字の扱いについて
-
verilogで、配列の一部をタスク...
-
ヒアドキュメントの中のfor文
-
配列をループでたくさん宣言し...
-
複数行のデータのPOST処理に関して
-
配列を回すとき、最後の要素だ...
-
String だと「 ByRef引数の型が...
-
配列一致(要素順番は違うが内容...
-
phpで、連想配列を普通の配列に...
-
OCI で、SELECT結果行数を取得...
-
MYSQLとPHPによって取得する多...
-
マッチング処理(1:N)
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
プルダウンメニューにDBの内容...
-
QuickForm createElement での ...
-
phpのin_array()でわからない事...
-
バッチでFTPコマンド
-
NGワード設定もしくはテキス...
-
2次元配列の値の受け渡しについ...
-
file_get_contents()にて文字化け
-
Zend_Form_Element_Hash
-
日付、時間の2段階でソート
-
サイト名を取得するPHP
-
codeigniterのページネーション...
-
しりとり 無限ループ?
-
phpとmysqlで「あいまい検索」...
-
listへのappendが出来ない件
-
テキストボックスの日本語をロ...
-
usortで3つの項目を昇順・降順...
-
1~100の数字の9の倍数だけ同じ...
-
pukiwikiのユーザ認証の設定で...
-
cakephp2.6でfindを使い合計値...
-
PHP5の外部コマンド実行で、バ...
おすすめ情報