みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

PHP CSVから条件にあう行を3行取りだしたい

以下のようなCSVがあったとします。(data.csv)価格で降順にソートしてあります。

line0,line1,line2
1,ぶどう,200(円)
2,なし,150(円)
3,りんご,100(円)
4,バナナ,80(円)
5,みかん,50(円)


ある果物を紹介するページがあったとして、
そのページには、他のオススメの果物として、csvからデータを読み込み、
その果物よりも安いもの3件を表示するという仕組みを作ろうと思っています。
ただ、安いものが3件無かった場合に、それよりも高いが、それに近い価格の果物を
あわせて3件まで紹介したいと思っています。


今作っているPHPは以下の通りです。
ページに紹介されている果物=($fruits),価格=($price) です。

<?php
$Data=file('/data.csv');
$j=0;
for($i=0;$i<sizeof($Data);$i++){
$line=explode(",",$Data[$i]);

#表示ページの果物とCSVのline1が違い、価格が$priceよりも小さいものを3件まで表示
if($fruits != line1 and $price >= line2 and $j<3 ){
    echo $line1 $line2.' </br>';
$j++;
}
}
?>

で、価格が低いものを3件まで表示することはできました。
ぶどう200円のページであれば、
2,なし,150(円)
3,りんご,100(円)
4,バナナ,80(円)
が表示されるようにはできました。

りんご100円のページには、
4,バナナ,80(円)
5,みかん,50(円)
の2件のみが表示されています。

上記りんごのように、安いものが3件なかった場合に、
それより価格が高いが一番近いものから順に3件になるまでデータを
取りだしたいと思っています。
今回のりんごであれば、リンゴより安い、バナナ80円、みかん50円、
それに加え、リンゴより高いがリンゴの価格に一番近い、なし150円を表示させたいです。
みかんの場合には、安いものがないため、高いがみかんに近いものから3つ
2,なし,150(円)
3,りんご,100(円)
4,バナナ,80(円)
を表示させたいです。

一体どうしたら良いのか、検討も付かず、教えて頂きたいです。
よろしくお願い致します。

投稿日時 - 2012-09-07 11:56:32

QNo.7685091

すぐに回答ほしいです

質問者が選んだベストアンサー

>その季節条件が同じものだけでとか~
価格以外の条件も参照するなら先の方法はマズいです。素直にデータを1つづつ回した方がよいでしょう。またfile()よりもfgetcsv()なら自動的に配列にしてくれるのでそちらがよいかと。

if(!$fh = fopen("data.csv", "r")) die("読み込み失敗");
$high = array();
$low = array();
while (($line = fgetcsv($fh, 1024, ",")) !== FALSE){
//自分なら何もしないで次へ
if($line[1] === $fruits) continue;

//以下でいろいろな条件を。例:季節が違えば無視して次へ
if($line[3] !== $季節) continue;


//条件をクリアしたら、高いものは逆順にしたいので先頭に入れていく
if( (int)$line[2] >= (int)$price){
array_unshift($high,$line);
//安いものは$lowの後ろに追加していく
}else{
array_push($low,$line);
}
}
//$lowと$highをくっつけて欲しい件数に切り詰めて…
$reco = array_splice(array_merge($low,$high),0,3);
//表示
print_r($reco);

※基本的に一気に出力しようとせず、1.処理(一旦必要なデータを作成する) 2.表示 にした方があとあと幸せになれます。煩雑な処理の上ましてやテーブルでの表示まで入ってくると自分でもわけが分からなくなって修正が大変です。

また、データは価格の降順なのに安いものが優先なので、処理が難しく感じられるのでしょう。
もしデータも昇順なら、現在の商品が出てきた段階で必要なオススメ件数が集まっていれば無駄なことをせずループ(forやwhile)から抜け出せます。件数が足りず自分より高いものが必要な場合でも、件数が集まった時点で終了できます。

※価格に(円)が入っているため、(int)$price として強制的に数字として評価していますが、思わぬ値になることもあります。価格に限らず、計算するものは数字だけの方が簡単ですよ。

思い通りに動いてくれた時は格別ですよね。頑張って下さい。

投稿日時 - 2012-09-10 23:54:14

お礼

随分とお礼が遅くなったのですが、いろいろ試行錯誤しながら、できるようになりました。

基本的な考え方や、csvの事などまでご丁寧にアドバイス頂き、本当に感謝しています。

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

投稿日時 - 2012-09-25 16:57:47

ANo.2

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(2)

ANo.1

いろいろな方法があると思いますが、考え方の一例として。
オススメしたい順番とはつまり、
[直近の安い商品(降順)] + [直近の高い商品(昇順)] の配列を作って、先頭からオススメ件数を取得すればよい、ということになりますよね?

//現在のページデータ。(line0はid? も既知としています)
list($id,$fruits,$price) = array(3,"りんご","100(円)");

$Data=file('data.csv');

//自分(現在の商品)が何番目か$nにキーを取得。りんごの場合なら[2]。
$n = array_search("$id,$fruits,$price\n",$Data);

//自分より安いものと高いものに分割する。
//安いもの--自分の次からが安いものなので、$n+1以降を$lowに取得
$low = array_splice($Data,$n+1);

//高いもの--残りをひっくり返して昇順に。[0]は自分なのでその次、つまり[1]以降を取得する。
$high = array_splice(array_reverse($Data),1);

//2つの配列をくっつけて欲しい件数を取得。
$reco = array_splice(array_merge($low, $high),0,3);

//後はforeachなどでお好きに整形出力
print_r($reco);

※動いているようですのでツッコミませんが、細かいタイプミスが多いのが気になります。
また操作しづらいのでcsvには通常(円)は入れない方がよいかと。

投稿日時 - 2012-09-08 20:36:28

補足

JaneDueさん
ありがとうございます。
うまく3行取り出せそうです。
先に必要な行を取り出すことで、スピードも向上しそうな気がしています。

3行取り出す時の条件として、例えば、100円以上のものだけとか、例えば果物の季節をCSVに入力しておき、その季節条件が同じものだけで、上記の3行を取り出すといったことは可能なのでしょうか?

>※動いているようですのでツッコミませんが、細かいタイプミスが多いのが気になります。
>また操作しづらいのでcsvには通常(円)は入れない方がよいかと。

ありがとうございます。
本当に、初心者の初心者であるため、不勉強な部分が多く恥ずかしいです><
また、何かあればなんでもおっしゃって下さい。

投稿日時 - 2012-09-10 15:20:16

あなたにオススメの質問