PHP5での3つの多次元配列を引っ付けて1つの多次元配列にする方法を教えてください。

また、ひとつになった多次元配列にソートを掛けたいのです。


(A)カテゴリ多次元配列
cat_id,cat_nm,cat_sort
1,ウェイクボード,B
2,スノーボード,A
3,サーフボード,C
4,ボードセイリング,D
5,カイトボード,E


(B)サブカテゴリ多次元配列
sub_id,sub_cat,sub_sort
1,スクール,a
2,トーイング,c
3,レンタル,d
4,販売,e
5,ツアー,b

(C)
cat_id,sub_id,flg
1,1,0
1,2,1
1,3,0
1,4,1
2,1,0
2,3,0
2,5,0
3,1,0
3,3,0
4,1,1


(C)の多次元配列に(A)と(B)をくっつけたいのです。
500文字に収まりませんでしたので、コメント欄にくっつけた多次元配列と、ソート後のイメージを追加しておきます。

回答の条件
  • 1人10回まで
  • 登録:2007/03/27 14:10:12
  • 終了:2007/03/28 12:13:54

ベストアンサー

id:nandedarou No.1

nandedarou回答回数230ベストアンサー獲得回数342007/03/27 17:26:10

ポイント100pt
// (A)の多次元配列が、$Aだとします。
// 例えば、echo $Cat['1']['cat_nm']; で 「ウェイクボード」 と表示されるように
// 配列の添え字をcat_idとする新しい、多次元配列$Catをつくる
foreach( $A as $row ){
    $cat_id  = $row['cat_id'];
    $Cat[ $cat_id ] = $row;
}

// (B)の多次元配列が、$Bだとします。
// 例えば、echo $Sub['1']['sub_cat']; で 「スクール」 と表示されるように
// 配列の添え字をsub_idとする新しい、多次元配列$Subをつくる
foreach( $B as $row ){
    $sub_id = $row['sub_id'];
    $Sub[ $sub_id ] = $row;
}

// (C)の多次元配列が、$Cだとします。
// 合体した新たな多次元配列$Newを作成する。
// その際、添え字を「Ba」というように、cat_sortとsub_sortを合成したものにする
foreach( $C as $row ){
    
    $cat_id  = $row['cat_id'];
    $sub_id  = $row['sub_id'];
    $key     = $Cat[ $cat_id ]['cat_sort'].$Sub[ $sub_id ]['sub_sort'];
    
    $New[ $key ] = array(
            'cat_id'   => $cat_id ,
            'cat_nm'   => $Cat[ $cat_id ]['cat_nm'  ] ,
            'cat_sort' => $Cat[ $cat_id ]['cat_sort'] ,
            'sub_id'   => $sub_id ,
            'sub_nm'   => $Sub[ $sub_id ]['sub_cat' ] ,
            'sub_sort' => $Sub[ $sub_id ]['sub_sort'] ,
            'flg'      => $row[ 'flg'   ] ,
            );
    
}

// $Newを添え字でソート(つまり、第一をcat_sortで、第二をsub_sortでソートしたことになる)
ksort($New);

以上、いかがでしょうか?

id:seadwell

kurukuru-nekoさま、コメントでここまでのご回答ありがとうございます。

nandedarouさま、1度ならず2度までもお手数をおかけしました。

また、私の説明不足とい誤字でご迷惑をおかけしたようです。


> もしかして、sub_nmとしたかったのでは?

ご指摘のとおりです。


それと、前回の回答の続きという注釈が必要でした。

http://q.hatena.ne.jp/1174771937


あと、cat_sortとsub_sortは説明がわかりやすくなるかと思い英字にしたのですが、実際は数字で行います。


言い訳ですが、寝てなくてモウロウとなっていました。

説明不足でホントすいませんm(_ _)m

前回の質問で回答を頂き、その後の応用はバッチリのつもりではいたのですが・・・。

一応ネットで、ソートや多次元配列の合体は検索掛けてみて、例文は見つけたのですが、今一自分のやりたいことに応用できませんでした。

とりあえず、お二人の教えていただいたコードを元に作成し、正常稼動するまで確認したいと思います。

また、無事実行したならコメントで改めて御礼を申したいと思います。

2007/03/27 22:54:26
  • id:seadwell
    (D)合体した新たな多次元配列
    cat_id,cat_nm,cat_sort,sub_id,sub_nm,sub_sort,flg
    1,ウェイクボード,B,1,スクール,a,0
    1,ウェイクボード,B,2,トーイング,c,1
    1,ウェイクボード,B,3,レンタル,d,0
    1,ウェイクボード,B,4,販売,e,1
    2,スノーボード,A,1,スクール,a,0
    2,スノーボード,A,3,レンタル,d,0
    2,スノーボード,A,5,ツアー,b,0
    3,サーフボード,C,1,スクール,a,0
    3,サーフボード,C,3,レンタル,d,0
    5,カイトボード,E,1,スクール,a,1


    くっついた(D)の多次元配列を第一をcat_sortで、第二をsub_sortでソート


    (D)新たな多次元配列(ソート後)
    cat_id,cat_nm,cat_sort,sub_id,sub_nm,sub_sort,flg
    2,スノーボード,A,1,スクール,a,0
    2,スノーボード,A,5,ツアー,b,0
    2,スノーボード,A,3,レンタル,d,0
    1,ウェイクボード,B,1,スクール,a,0
    1,ウェイクボード,B,2,トーイング,c,1
    1,ウェイクボード,B,3,レンタル,d,0
    1,ウェイクボード,B,4,販売,e,1
    3,サーフボード,C,1,スクール,a,0
    3,サーフボード,C,3,レンタル,d,0
    5,カイトボード,E,1,スクール,a,1


    以上のようにソートしたいのですが、自力ではできませんでした。
    どなたか助けてください!!
  • id:kurukuru-neko
    # $a/$b/$cに値が入っているとする。
    $aの配列の連想キーが不明なので

    #連想キーを cat_id/sub_idの値で作り直す
    $cat_id = array();
    foreach( $a as $var ) {
    $cat_id[ $var['cat_id'] ] = array( 'cat_num' =>$var['cat_nm'],'cat_sort'=>$var['cat_sort']);
    };

    $sub_id = array();
    foreach( $b as $var ) {
    $sub_id[ $var['sub_id'] ] = array( 'sub_cat' =>$var['sub_cat'],'sub_sort'=>$var['sub_sort']);
    };

    # $cからcat_id,sub_idを連想キーにして
    # $cmergeを作成
    #
    $cmerge = array();
    foreach ( $c as $var) {
    $index = $var['cat_id'] . "-" . $var['sub_id'];;
    $cmerge[$index] = array_merge($var,$cat_id[ $var['cat_id']] ,$sub_id[ $var['sub_id']] );
    };

    # 連想キーでソート
    ksort($cmerge);
    print_r($cmerge);

    # 自分でソートしたい場合
    function mysort($k1,$k2) {
    if( $k1['cat_sort'] == $k2['cat_sort'] ) {
    if( $k1['sub_sort'] == $k2['sub_sort'] ) {
    return 0;
    };
    if( $k1['sub_sort'] > $k2['sub_sort'] ) {
    return 1;
    };
    return 0;
    };
    if( $k1['cat_sort'] >= $k2['cat_sort'] ) {
    return 1;
    };
    return -1;

    };
    usort($cmerge,'mysort');
    print_r($cmerge);

  • id:nandedarou
    私の回答に対する補足です。

    ●もし、(A)や(B)の多次元配列がもともとMySQLのテーブルのデータならば、次のようにデータベースからデータを取り出す時点で、$Catと$Subに格納した方がいいと思います。(前回のご質問に対する回答では、私はそれを想定しておりました。)

    // (A) テーブル名が「cat_tb」の場合
    $sql = 'SELECT * FROM cat_tb ;';
    $res = mysql_query($sql);
    while ($row = mysql_fetch_assoc($res)) {
    $Cat[ $row['cat_id'] ] = $row;
    }

    // (B) テーブル名が「sub_tb」の場合
    $sql = 'SELECT * FROM sub_tb ;';
    $res = mysql_query($sql);
    while ($row = mysql_fetch_assoc($res)) {
    $Sub[ $row['sub_id'] ] = $row;
    }

    ●私の回答は、cat_sortが1文字であることを想定しています。
    cat_sortが2文字以上あり得る場合は、
    $keyに値を入れる部分を下記のように変更して下さい。
    $key = $Cat[ $cat_id ]['cat_sort'].'_'.$Sub[ $sub_id ]['sub_sort'];
    ※cat_sortに、'_'が含まれる余地がある場合は、'_'をcat_sortに含まれる余地のない文字に変更して下さい。(sub_sortには、'_'が含まれていても構いません。)
    ※ソートのロジックは上記kurukuru-nekoさんの最初のロジックと一緒です。ただ、$indexの値が…。

    ●なお、質問文でちょっと気になったのが、(B)のsub_catというフィールド名ですが、もしかして、sub_nmとしたかったのでは?とりあえず、sub_catのままで回答しました。
  • id:kurukuru-neko
    # 自分でソートしたい場合
    function mysort($k1,$k2) {
    if( $k1['cat_sort'] == $k2['cat_sort'] ) {
    if( $k1['sub_sort'] == $k2['sub_sort'] ) {
    return 0;
    };
    if( $k1['sub_sort'] > $k2['sub_sort'] ) {
    return 1;
    };
    return -1; // ← 間違い
    };
    if( $k1['cat_sort'] >= $k2['cat_sort'] ) {
    return 1;
    };
    return -1;

    };
  • id:kurukuru-neko
    A,B,Cがデータベースなら
    Aカテゴリ多次元配列
    cat_id,cat_nm,cat_sort
    Bサブカテゴリ多次元配列
    sub_id,sub_cat,sub_sort
    C??
    cat_id,sub_id,flg

    ソースがSQL上のDBなら
    最初にSQLでA/B/Cのテーブルを

    SQLで選択した方が簡単
    (sub_nmはないのでsub_catだとおもいますが)
    select
    cat_id,cat_nm,cat_sort,sub_id,sub_nm,sub_sort,flg from
    c left join a using(cat_id) left join b using(sub_id)
    order by cat_sort,sub_id;
  • id:nandedarou
    >SQLで選択した方が簡単
    前回の質問は、私が回答したのでわかるのですが、
    (C)のテーブルは、SQLを実行した結果のテーブルです。

    usingなども使って、いろいろやってみましたが、一つのSQL文で処理するのは、難しそうです。(※入れ子状のSELECT FROMが動作すれば、何でもありですが、Mysqlではエラーがでます。)

    もし、一回のSQLでやる方法があるなら、私も知りたいのでお願いします。
  • id:nandedarou
    >あと、cat_sortとsub_sortは説明がわかりやすくなるかと思い英字にしたのですが、実際は数字で行います。

    数字が、2桁になりうる場合は、ソートで問題になります。
    文字としてソートするか数値としてソートするかで結果が異なるからです。(ksort関数の第二引数で指定する方法もありますが、今回は二つの数字を合わせるので、それでもダメです。)
    数字としては、2 < 10
    文字としては、2 > 10

    そこで、
    2の前に0を付ければ、文字として比較しても 02 < 10 となります。

    私の回答$keyに値をセットする部分を次のように変更して下さい。
    $key = sprintf( "%02d", $Cat[ $cat_id ]['cat_sort']).'_'.sprintf( "%02d", $Sub[ $sub_id ]['sub_sort'] );

    結果は、例えば cat_id が「2」で、sub_sort が 「5」のとき、$key は、「02_05」 となります。

    ※上記の "%02d" の 2 が、2桁の意味ですので、99まで、大丈夫です。(3とすれば、999まで大丈夫です。)
  • id:nandedarou
    今実験したところ、次の二つを変更すれば、大丈夫でした!
    (直前の方法でも大丈夫ですが、こちらの方が簡単です。)

    $key = $Cat[ $cat_id ]['cat_sort'].'_'.$Sub[ $sub_id ]['sub_sort'];

    ksort($New, SORT_NUMERIC );
  • id:nandedarou
    >> もしかして、sub_nmとしたかったのでは?
    >ご指摘のとおりです。
    では、次のように変更して下さい。

    (変更前)
    'sub_nm' => $Sub[ $sub_id ]['sub_cat' ] ,

    (変更後)
    'sub_nm' => $Sub[ $sub_id ]['sub_nm' ] ,
  • id:kurukuru-neko
    >order by cat_sort,sub_id;

    ソート条件違いました
    order by cat_sort,sub_sort
    ですね。



  • id:kurukuru-neko

    >もし、一回のSQLでやる方法があるなら、
    >私も知りたいのでお願いします。

    Cの検索条件をみていないのでなんともいえませんが
    SQLの結果とすれば単純に

    create temporay TABLE
    で一時テーブルを作成して
    selectをinsertで検索結果をいれて
    しまう手もあるかな。

  • id:seadwell
    できましたー!!
    すったもんだの挙句に、無事正常動作を確認しました^^;
    まだ、次段階で問題も山積ですが、今回の問題は解決いたしました。
    kurukuru-nekoさま、nandedarouさまありがとうございました。

    報告に時間が掛かったのは、DBからTB読み込みの際でいろいろ試していたことと、あと、出力がsmartyを使用しているのでforeachでのループで同じカテゴリ内では同一カテゴリを何回も出力しないようにすることに時間が掛かってしまいました。
    せっかくsmartyを使っているのでテンプレート内にプログラムをあまり書きたくなかったのですが、今回は仕方なく稚拙ですがforeach内でIfを使いました。
    何故か?ksort($New, SORT_NUMERIC );がうまくソート出力されなかったので、私にわかりやすかったsprintfを使用しました。$smarty->assignのせいかな?
    今回、配列に関してな~んも理解していなかったことがよくわかりました。
    あと気がついたら爆睡してました^^;


    nandedarouさま。
    あなたの回答は、知識の奥深さもさることながら、人柄が伝わってきます。
    短い文章の場合でも『どうすれば相手に伝わるか?』人並み以上に一生懸命に考えられていることが伝わりますし、小さなことでもいい加減に答えられない人柄がわかります。
    私の質問にお答えくださり、当方の問題は無事解決しました(現段階ですが^^;)ことはうれしいのですが、それ以上に親身になっていただいていることが非常にうれしく思います。


    kurukuru-nekoさま。
    コメントなのにあそこまで詳しく回答頂き、お二人の回答を照らし合わせることでより理解が深まりました。
    当方の勝手な考えで申し訳ないのですが、お答えいただいた方の回答をきちんと試すまで一時回答を中断するようにしていますので今回は御礼ができませんが、私はド素人なのでまた助けてください^^
    そのときは、ぜひ回答欄にご記入をお願いします。
    usortは勉強になりました。今の私には難易度が高くちゃんと理解してから今後使いたいと思います。
  • id:nandedarou
    ●kurukuru-neko 様
    >selectをinsertで検索結果をいれて
    >しまう手もあるかな。
    確かに、そこまですればできるでしょうが、一回のSQLというイメージではないですね?

    前回のseadwellさんのご質問は、 http://q.hatena.ne.jp/1174771937 です。

    テーブルは、もともと、4つ(←seadwellさんの提示した3つと、私の提案で追加した1つ)あります。(cat_sortとsub_sortに相当するフィールドはありませんした。)

    前回の私の回答のSQLでは、カテゴリID,サブカテゴリID,登録というフィールド(今回の質問でいうとcat_id,sub_id,flgというフィールド)で結果を返すのですが、
    前回の段階で、カテゴリID,カテゴリ名,サブカテゴリID,サブカテゴリ名,登録というフィールドで結果を返すことができるなら、今回の回答もそれをちょっと変更すれば、できると思うのです。

    私はやろうと思えば一回のSQLできると思っていましたが、実際やろうとしたところ、できませんでした。 kurukuru-nekoさんなら、何かうまいやり方を知っている可能性もあります。もし、お時間があったら、前回の質問挑戦して見て下さい。

    ●seadwell 様
    ksort($New, SORT_NUMERIC );私の環境と私の実験した条件で,
    たまたまうまくいっただけだったのかも…。確かに私が実際やる場合も、sprintfを選択するかも知れません。sprintfの方が、絶対に間違いなくソートできることを実感できますから。

    私にはもったいないお褒めの言葉ありがとうございます。
    かなり、正確な分析です。質問者に伝わることが私の喜びです。さらに、回答しながら自分の腕が磨けるので、自分の課題としても取り組んでおります。

    なるほど、やはりsmartyですね。すぐに出力せず、配列に結果を入れていたので、そんな気がしていました。私もsmartyを使っています。Ifを使うのはしょうがないでしょうね。

    それでは、頑張ってください。私もそろそろ、本業に戻らなければ…。
  • id:kurukuru-neko
    >一回のSQLというイメージではないですね

    # カテゴリー
    create table a(
    cat_id int,cat_nm char(32),
    cat_sort char(1)
    primary key (cat_id)
    );
    # サブカテゴリー
    create table b (
    sub_id int,sub_cat char(32),
    sub_sort char(1),
    primary key (sub_id)
    );
    # カテゴリー+サブカテゴリー
    create table c (
    cat_id int, sub_id int,
    primary key (cat_id,sub_id)
    );

    # ユーザー
    create table u (
    userid int,cat_id int,sub_id int,
    PRIMARY KEY (userid,cat_id,sub_id)
    );

    a/b/c/uのテーブルがあれば
    ユーザーID 1番の人のデータを
    作成するとすると

    select
    c.cat_id,cat_nm,cat_sort,
    c.sub_id,sub_cat,
    sub_sort,
    if(userid is null,0,1) as flg
    from
    c
    left join a using(cat_id)
    left join b using(sub_id)
    left join u
    on u.cat_id = c.cat_id and u.sub_id = c.sub_id and u.userid=1
    order by cat_sort,sub_sort;

    c/uのテーブルは使い方によっては
    # カテゴリー+サブカテゴリー
    create table c (
    catsub_id int,
    cat_id int, sub_id int,
    primary key (catsub_id),
    unique key (cat_id,sub_id)
    );

    # ユーザー
    create table u (
    userid int,catsub_id int,
    PRIMARY KEY (userid,catsub_id)
    );

  • id:kurukuru-neko

    >ただ、$indexの値が…。

    思いっきり間違ってますね。
    $index = $cat_id[ $var['cat_id']]['cat_sort'] . "-" . $sub_id[ $var['sub_id']]['sub_sort'];

    sprintfで修正した場合は、
    ソート列が文字だと
    $index = sprintf("%-2.2s%-2.2s",
    $cat_id[ $var['cat_id']]['cat_sort'],
    $sub_id[ $var['sub_id']]['sub_sort']
    );

    ksortは、SORT_STRING の指定がしなくても
    文字型なので動作するとは思います。

    数値だと小数点以下にするか

    カテゴリー*100+サブカテゴリーのように
    数値に変換する必要があります。

    小数点に変換
    カテゴリー.サブカテゴリー
    $index = sprintf("%d.%d",
    $cat_id[ $var['cat_id']]['cat_sort'],
    $sub_id[ $var['sub_id']]['sub_sort']
    );

    $index = 0
    +$cat_id[ $var['cat_id']]['cat_sort']*100
    +$sub_id[ $var['sub_id']]['sub_sort']
    ;

    ksortは、SORT_NUMERICの指定をする。
    指定しないでも整数に変換されて
    動作するとは思います。
  • id:nandedarou
    ●kurukuru-neko 様
    SQL文ありがとうございます。
    なるほど!left join ~ usingをその順番で使えばうまくいくのですね。勉強になりました。

    前回のseadwellさんのご質問 http://q.hatena.ne.jp/1174771937 の「この質問・回答へコメント」欄に、教えていただいた方法で、SQL文を掲載しておきます。
    (※もちろん、kurukuru-neko 様に教えていただいた旨もお書きします。)

    ●seadwell 様
    2つ上のkurukuru-nekoさんのコメントにある
    selectから;までのSQL文を実行するのが一番スマートな方法だと思われます。
  • id:seadwell
    お二人の会話が私には高度すぎて・・・
    コメントのお返しをする間がありません^^;

    まだ、SQLの表結合をしっかり理解していない私なので、教えていただいたSQL文を完全に自分のものにしていませんが、ご親切なkurukuru-nekoさまとnandedarouさまに改めて御礼を申し上げます。
    簡単ですが、ほんとのほんとに感謝しています。

    SQL表結合をネット検索でいろいろ見ているのですが、『なんか、使いこなすと非常に便利なのでは・・・、今まで非常に遠回りで稚拙なSQLを発行していたのでは・・・、』と思い、コメントで質問するのもなんですから新たに質問を設けました。
    http://q.hatena.ne.jp/1175208593
    しつこくお世話になりますが、よろしくお願いします。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません