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

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

ただいまの
回答率

88.03%

PHPのループ内の条件分岐で振り分けた項目の並び替え

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,910

score 609

次の様なコードで一致した項目を並び替えて先頭に表示させるにはどうしたら良いでしょうか?
単純に$keyと$itemsの配列をarray_replaceで置き換えようとしてもうまくいかずに頭を悩ませています。
$key = array_flip( $key );
foreach ( $items as $item ) {
    if ( isset( $key[ $item -> name ] ) ) {
        echo '<li>Success: ' . $item -> name . '</li>';
    } else {
        echo '<li>Fail: ' . $item -> name . '</li>';
    }
}

現在の表示結果
  • Success: A
  • Fail: B
  • Success: C
  • Fail: D

求める表示結果
  • Success: A
  • Success: C
  • Fail: B
  • Fail: D

$itemsの内容
array(3) {
  [0]=>
  object(stdClass)#0 (10) {
    ["name"]=>
    string(1) "A"
    ~省略~
  }
  [1]=>
  object(stdClass)#1 (10) {
    ["name"]=>
    string(1) "B"
    ~省略~
  }
  [2]=>
  object(stdClass)#2 (10) {
    ["name"]=>
    string(1) "C"
    ~省略~
  }
  [3]=>
  object(stdClass)#3 (10) {
    ["name"]=>
    string(1) "D"
    ~省略~
  }
}

$keyの内容
array(2) {
  [0]=>
  string(1) "A"
  [1]=>
  string(1) "C"
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 4

checkベストアンサー

+2

$items 自体を並べ替えたいわけではなく、表示順をどうにかしたいだけであれば、2回 foreach するいのが一番簡単だと思います。

<?php
$key = [
    'A',
    'C',
];

$items = [
    (object)['name' => 'A'],
    (object)['name' => 'B'],
    (object)['name' => 'C'],
    (object)['name' => 'D'],
];

$key = array_flip( $key );

foreach ( $items as $item ) {
    if ( isset( $key[ $item -> name ] ) ) {
        echo '<li>Success: ' . $item -> name . "</li>\n";
    }
}

foreach ( $items as $item ) {
    if ( !isset( $key[ $item -> name ] ) ) {
        echo '<li>Fail: ' . $item -> name . "</li>\n";
    }
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/06/02 23:13

    ngyukiさん
    回答して下さりありがとうございます。
    分かりやすくてシンプルですね。
    何となくループを1回に抑えたい気もしますが、とても分かりやすいのでこちらのコードを使わせて頂こうと思います。

    キャンセル

+2

$items の並び順そのものを変えたいのであれば、次のように uksort で比較関数を上手く作るとかでもいいかもしれません(それだけの目的にしては大げさかもしれません)。

<?php
$key = [
    'A',
    'C',
];

$items = [
    (object)['name' => 'A'],
    (object)['name' => 'B'],
    (object)['name' => 'C'],
    (object)['name' => 'D'],
];

$key = array_flip($key);

uksort($items, function ($a, $b) use ($key, $items) {
    // `name` プロパティが `$key` にあるものが先
    $aa = isset($key[$items[$a]->name]);
    $bb = isset($key[$items[$b]->name]);
    if ($aa > $bb) {
        return -1;
    } elseif ($aa < $bb) {
        return +1;
    }
    // 元の配列のインデックスが最初のものが先
    if ($a < $b) {
        return -1;
    } elseif ($a > $b) {
        return +1;
    }
    return 0;
});

foreach ( $items as $item ) {
    if ( isset( $key[ $item -> name ] ) ) {
        echo '<li>Success: ' . $item -> name . "</li>\n";
    } else {
        echo '<li>Fail: ' . $item -> name . "</li>\n";
    }
}


投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/06/02 23:21

    違うケースまで提示して下さりありがとうございます。
    どれが効率が良く適した処理なのかというのは私にはまだ判断出来ないので、今回は見た目に分かりやすい方を選ばせて頂きます。
    ただ、頂いたコードに対する私の理解が不足しているのであくまでも素人考えというものですが、ループが1回で済むのは何となくスッキリしていていいですね。
    こちらの比較関数の部分も早速勉強しようと思います。:)

    キャンセル

+1

こんな感じでしょうか。
$key = array_flip($key);

// 有効な値を含む配列を生成
$items_success = array_filter($items, function ($item) use ($key) {
    return isset($key[$item->name]);
});
// 無効の値を含む配列を生成(有効な値を含む配列との差分で取得)
$items_fail = array_diff_key($items, $items_success);

// それぞれの配列を表示
foreach ($items_success as $item) {
    echo '<li>Success: ' . $item->name . '</li>';
}
foreach ($items_fail as $item) {
    echo '<li>Fail: ' . $item->name . '</li>';
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/06/02 23:02

    sounisi5011さん
    回答して下さりありがとうございます。
    頂いた内容で求める表示が得られました。
    また配列の関数やクロージャへの変数の引き継ぎなども頂いたコードを理解するために調べるうちに学ぶ事が出来てとても勉強になりました。:)

    キャンセル

0

こちらの回答は間違えて投稿してしまいました…。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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