スレッド表示 | フラット表示〕 全トピック 920 件中 383 番目 次≫ ≪前

配列の並び替え

created: 2005-08-27 14:05 | modified: 2005-08-28 00:32 | reply: 8

[2500] 配列の並び替え

user: のり | created: 2005-08-27 14:05
下記のようなCSVデータがあるのですが、
4列目、3列目、1列目でソートしたいのですが、
USORTで上手くいきませんが、どのような手法があるのでしょうか?

a00001 2940 3 08/10/05
a00002 3045 3 08/17/05
a00003 4095 4 08/17/05
a00004 3045 3 08/10/05
a00006 3045 4 08/10/05
<求めたい結果>
a00001 2940 3 08/10/05
a00004 3045 3 08/10/05
a00006 3045 4 08/10/05
a00002 3045 3 08/17/05
a00004 3045 3 08/10/05
reply: 2501 返信 編集 削除

[2501] 複数キーによる配列の並べ替え

user: ゆうじ | created: 2005-08-27 15:12
こんにちは。

> USORTで上手くいきませんが、どのような手法があるのでしょうか?

手法と言ってもusortの第2引数に与える
ユーザ定義の比較関数で並べ替えたい結果を返すよう書くのみです。
ユーザ定義の比較関数の書き方がわからないということですかね?


比較関数の書式はこうです。
integer comp_function_name ( $rec1, $rec2 )

引数の $rec1 と $rec2 は比較するレコード、
戻り値は、0, 1, -1 のいずれかです。

$rec1 と $rec2 を比較して、
並べ替えないなら戻り値 0
$rec1 を先にするなら戻り値 -1(負の数)
$rec2 を先にするなら戻り値 1(正の数)
のいずれかを返すように書きます。

キー 3, 2, 0 が対象となるようですので
キー 3 の比較が 0 を返す場合にキー 2 の比較式を入れ子に、
さらにキー 2 の比較が 0 を返す場合にキー 0 の比較式を入れ子に、
と言った具合に書きます。

キー 3, 2, 0の順に全て昇順で並べ替える例)
function ucmp ( $rec1, $rec2 )
{
// キー 3 の比較式
if ($rec1[3] == $rec2[3]) {
// キー 2 の比較式
if ($rec1[2] == $rec2[2]) {
// キー 0 の比較式
if ($rec1[0] == $rec2[0]) {
return 0;
} elseif ($rec1[0] < $rec2[0]) {
return -1;
} else {
return 1;
}
} elseif ($rec1[2] < $rec2[2]) {
return -1;
} else {
return 1;
}
} elseif ($rec1[3] < $rec2[3]) {
return -1;
} else {
return 1;
}
}

キー3が日付のようですので、
比較の際これにもうひと工夫必要です。

# もし理解できたら php-users-ml にも必ず報告を♪
Parent: 2500  reply: 2502 2505 返信 編集 削除

[2502] Re.複数キーによる配列の並べ替え

user: のり | created: 2005-08-27 16:20
ゆうじさん、ありがとうございます。

私の力では、日付のところを
if (strtotime($rec1[22]) == strtotime($rec2[22])) {

としたのですが、ダメです。

もう少しお力をお借り出来れば嬉しい限りです。


> function ucmp ( $rec1, $rec2 )
> {
> // キー 3 の比較式
> if ($rec1[3] == $rec2[3]) {
> // キー 2 の比較式
> if ($rec1[2] == $rec2[2]) {
> // キー 0 の比較式
> if ($rec1[0] == $rec2[0]) {
> return 0;
> } elseif ($rec1[0] < $rec2[0]) {
> return -1;
> } else {
> return 1;
> }
> } elseif ($rec1[2] < $rec2[2]) {
> return -1;
> } else {
> return 1;
> }
> } elseif ($rec1[3] < $rec2[3]) {
> return -1;
> } else {
> return 1;
> }
> }
Parent: 2501  reply: 2503 返信 編集 削除

[2503] Re.複数キーによる配列の並べ替え

user: ゆうじ | created: 2005-08-27 17:09
echo strtotime($rec1[22]) とかやって、
思ったとおりの結果を返してくれない原因を調べてみましたか?
何もかも頼られても困ります。自分でできることは自分でしましょうよ。

日付の書式は mm/dd/yy ですよね。
これは strtotime関数が処理できる英文の日付文字列でないのが原因でしょう。
http://jp.php.net/manual/ja/function.strtotime.php
http://www.gnu.org/software/tar/manual/html_chapter/tar_7.html

$time1 = explode('/', $rec1[22]);
$time1 = sprintf("%02d%02d%02d", $time1[2],$time1[0],$time1[1]);

$time2 = explode('/', $rec2[22]);
$time2 = sprintf("%02d%02d%02d", $time2[2],$time2[0],$time2[1]);

if ($time1 == $time2) {



}

上記のように日付の書式を一旦分解して yymmdd に並べ替えれば
文字列として単純に比較できます。
Parent: 2502  返信 編集 削除

[2505] うまく動作しないのですが・・・

user: のり | created: 2005-08-27 19:11
ゆうじ様、色々とアドバイスありがとうございます。

色々と試しているのですが、下記のソースで動作しません。
恐縮だとは思いますが、お知恵を貸してください。
ちなみに、データを21列目ですが050810のように直して
おりますが・・・。


<?php
$datafile = "Adata.csv";
$file = array();
$fp = fopen($datafile, "r");
while ($data = fgets($fp, filesize($datafile)+1)) {
list($id) = explode(",", $data);

$file[$id] = $data;

}

function ucmp ( $rec1, $rec2 ){
// キー 3 の比較式
if ($rec1[21] == $rec2[21]) {
// キー 2 の比較式
if ($rec1[10] == $rec2[10]) {
// キー 0 の比較式
if ($rec1[0] == $rec2[0]) {
return 0;
} elseif ($rec1[0] < $rec2[0]) {
return -1;
} else {
return 1;
}
} elseif ($rec1[10] < $rec2[10]) {
return -1;
} else {
return 1;
}
} elseif ($rec1[21] < $rec2[21]) {
return -1;
} else {
return 1;
}
}

uasort($file , "ucmp");

foreach($file as $val) {
list($a,$b,$c,$d,$e,$f,$g,$h,$i,$j,$k,$l,$m,$n,$o,$p,$q,$r,$s,$t,$u,$v) = explode(",",$val);

echo $a." ";
echo $b." ";
//echo $c." ";
echo $c." ";
echo $v."<br> ";

}




?>
Parent: 2501  reply: 2506 2508 返信 編集 削除

[2506] 割り込んでご免なさい。

user: ach | created: 2005-08-27 19:39
$recってこのコードだと文字列がはいるような気がするんですが・・・

横からくちだしたんで見当はずれのこと言ってるかもしれませんが、エラーリポートをE_ALLにしてチェックしてみて下さい。


あ、あと何回か書き込みしましたけど、挨拶してませんでした、ご免なさい。
え?っと・・・初めましてorz
Parent: 2505  返信 編集 削除

[2508] Re. うまく動作しないのですが・・・

user: ゆうじ | created: 2005-08-27 21:17
while ($data = fgets($fp, filesize($datafile)+1)) {
list($id) = explode(",", $data);
$file[$id] = $data;
}

achさんのおっしゃる通り、
この処理の後 $file は文字列の入った一次元配列なってると思いますよ。
この状態で複数のキーで並べ替えは不可能です。
下のように $fileには、配列を格納するよう手直ししてください。

while ($data = fgets($fp, filesize($datafile)+1)) {
$file[] = explode(",", $data);
}


それから自分が考えている通りの結果が得られているか
一つ一つ処理結果を var_dump($file) とかで確かめながら
やってみてください。
遠回りのようですがそのほうが明らかに早く理解出来ると思います。

# ach さんこんばんわ。
# 横からでも上からでも割り込み大歓迎です。
# このBBSはパブリックなところが売り(?)ですんで気になさらず。
# 今後とも宜しくお願いします。
Parent: 2505  reply: 2509 返信 編集 削除

[2509] 本当にありがとうございました。

user: のり | created: 2005-08-27 23:50
ゆうじ様、ach様

↓の修正で思い通りの結果が得られました。
まだまだ、至らない私ですが色々学ぶ事が出来ありがとう
ございました。

>while ($data = fgets($fp, filesize($datafile)+1))
>{ list($id) = explode(",", $data); $file[$id] = $data;}
Parent: 2508  reply: 2510 返信 編集 削除

[2510] お疲れ様でした。

user: ゆうじ | created: 2005-08-28 00:32
お疲れ様でした。

おせっかいですが
php-users-ml にもいくつかレスが付いてましたよ。
そちらにも必ずお礼と『報告』をしておきましょう。

以前の投稿にも報告されてないようですが、
解決できたにせよ出来なかったにせよ、
何が原因で、どこをどう直したところ、どういう結果になって、
どういうことが理解できたのかを報告しましょう。

それがこうしたフォラムで回答を頂いた方への誠意です。
答える側の立場になって考えればなぜそれが必要かわかると思います。

ピンとこなければこことか読むと大変参考になります。
●技術系メーリングリストで質問するときのパターン・ランゲージ
http://www.hyuki.com/writing/techask.html
Parent: 2509  返信 編集 削除
スレッド表示 | フラット表示〕 全トピック 920 件中 383 番目 次≫ ≪前
ページの一番上へ
Googleグックマークに登録 Yahooグックマークに登録 livedoorクリップに登録 @niftyクリップに登録 はてなブックマークに登録 deliciousに登録 Buzzurlに登録 FC2ブックマークに登録
最近更新された掲示板トピックス
管理人Blog
Yahoo Search

最近更新したNote
PHPマニュアル
今日のブックマーク
PHPマニュアル関数検索
関数名を入力し検索ボタンをクリック↑