質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.10%

PHPの多次元連想配列を、不定キーでソートできますか?

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 603

score 13

前提・実現したいこと

PHPで多次元連想配列をソートする機能を作っています。

該当のソースコードの出力結果である
$post_datasですと「1,3,2,4」の順になりますが、
$post_idsと同様に「1,2,3,4」の順にソートしたいです。

該当のソースコード

以下がソート対象である$post_datasを生成するコードになります。
最後のvar_export( $post_datas )で「1,3,2,4」の順になります。
※これは変更できません。

function get_post_type( $post_id ){
    if( $post_id & 1 ){
        $number = 'odd';
    }else{
        $number = 'even';
    }
    return $number;
}

function get_post_data( $post_id ){
    $post_type = get_post_type($post_id);
    $post_data = [ 'post_type'=>$post_type, $post_type.'_id'=>$post_id ];
    return $post_data;
}

$post_ids = [1,2,3,4];
foreach( $post_ids as $post_id ){
    $post_data = get_post_data($post_id);
    $post_type = $post_data['post_type'];
    if( $post_type=='odd' ){
        $odd_datas[] = $post_data;
    }else{
        $even_datas[] = $post_data;
    }
}

$post_datas = array_merge( $odd_datas, $even_datas );
var_export( $post_datas ); // 1,3,2,4の順になる

試したこと

ソートするキーは「××_id」なので、このようにソートのためのコードを実行しました。

しかし、ソートされるキーが不定なためでしょうか、次のエラーになってしまいます。

foreach($post_datas as $key=>$value){
    $post_type = $post_data['post_type'];
    $result[$key] = $value[$post_type.'_id'];    
}
array_multisort( $result, SORT_ASC, $post_datas );

エラーメッセージ

そのエラーがこちらです。

PHP Notice:  Undefined index: even_id in /test.php on line 35
PHP Notice:  Undefined index: even_id in /test.php on line 35

補足情報

該当のソースコードにある$post_datasに、$post_type.'_id' => $post_idだけでなく'post_id' => $post_idなどの不定ではないキーを追加すればいい話ですが、それはなしで、不定のキーとしての方法を模索しています。

なお、ソートキーは「××_id」ですが、その「××」の部分は必ず「$post_typeの値」が入ります。

以上になります。不備等ございましたらご指摘ください。
ご回答宜しくお願い申し上げます。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • m.ts10806

    2019/11/07 10:05

    質問を編集して「コピペで他社が再現できる状態」にしてください。

    キャンセル

  • tarakorakko

    2019/11/07 10:13

    どなたでもコピペで再現できるはずと思いますが、どのようにお試しになりましたか?

    キャンセル

  • m.ts10806

    2019/11/07 10:15

    失礼。コードの後半見落としてました

    キャンセル

回答 2

checkベストアンサー

+3

usort($post_datas,function($x,$y){
  return $x[$x["post_type"]."_id"]-$y[$y["post_type"]."_id"];
});

usortの仕組み

マイナス「-」の意味

$xの○○○_id要素と$yの○○○_id要素の大きさを比べて
$xが大きければ$x[○○○]-$y[○○○]はプラスになり、小さければマイナスになります。
usortは2値をくらべてマイナスなら前に、プラスなら後にソートする処理です
ちゃんと書くならこんな感じです

usort($post_datas,function($x,$y){
  $ret=1; 
  if($x[$x["post_type"]."_id"]<$y[$y["post_type"]."_id"]) $ret=-1;
  return $ret;
});


三項演算でかくとちょっと見やすくなります

usort($post_datas,function($x,$y){
  return $x[$x["post_type"]."_id"]<$y[$y["post_type"]."_id"])?-1:1;
});


結局戻り値はプラスかマイナス(0も含め)しかみてないので、
比較するのが数値であれば引き算すれば事足りるわけです。

post_ids順

usort($post_datas,function($x,$y) use($post_ids){
  return array_search($x[$x["post_type"]."_id"],$post_ids)-array_search($y[$y["post_type"]."_id"],$post_ids);
});

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/11/07 10:23 編集

    具体的な書き方をありがとうございます。usortが初見なので解読に手こずりそうです。もしよろしければ「$y」の手前の「-」の意味だけ教えて頂けませんでしょうか。

    キャンセル

  • 2019/11/07 10:32

    すみません、そちら、「××_idが若い順でソート」されていませんでしょうか?
    目的は「$post_idsの並びと同様にソート」でしたので、もう少し考えさせてください。

    キャンセル

  • 2019/11/07 10:36 編集

    > 「$post_idsの並びと同様にソート」

    ちょっと仕様が違うみたいですね、post_ids順追記しました
    post_ids順でやる場合は絶対にpost_idsはロジック的に
    ユニークなデータでないといけませんのでご注意ください

    キャンセル

  • 2019/11/07 11:02 編集

    ここまで詳しくご説明いただけるとは考えてもみませんでした。php.netよりわかりやすいですwどうもありがとうございます。思っていた通りの機能が実装できました。

    ところで「>ユニークなデータでないといけません」とは、「useで使うから、$post_idsという変数名は1つしか使えません」という意味でよろしいでしょうか?

    キャンセル

+3

比較用の配列を作らずに、2要素を受け取って比較結果を返す関数を引数に渡せるusortを使うがいいのではないかと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/11/07 10:25

    ありがとうございます。調べてみます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る