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

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

ただいまの
回答率

90.62%

  • PHP

    19833questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

二つの多次元配列を比較して、片方にだけ含まれるものを抽出する方法

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 2,299

zico_teratail

score 561

二つの多次元配列の片方にだけ含まれるものを抽出したいです。

具体的には、以下のような配列Aと配列Bを比べて、片方にだけ含まれる組み合わせ、すなわちこの場合は
[flag] => 88
[status] => 25

[flag] => 122
[status] => 25
の組み合わせが、最終的に得たい結果です。

配列A
Array
(
    [0] => Array
        (
            [flag] => 2
            [status] => 25
        )

    [1] => Array
        (
            [flag] => 64
            [status] => 25
        )

)

配列B
Array
(
   [0] => Array
        (
            [flag] => 122
            [status] => 25
        ) 
   [1] => Array
        (
            [flag] => 2
            [status] => 25
        )

    [2] => Array
        (
            [flag] => 64
            [status] => 25
        )

    [3] => Array
        (
            [flag] => 88
            [status] => 25
        )

)

試したコードは以下の通り。

<?php
//配列A
$ArrayA[] = array('flag'=>'2','status'=>'25');
$ArrayA[] = array('flag'=>'64','status'=>'25');

//配列B
$ArrayB[] = array('flag'=>'122','status'=>'25');
$ArrayB[] = array('flag'=>'2','status'=>'25');
$ArrayB[] = array('flag'=>'64','status'=>'25');
$ArrayB[] = array('flag'=>'88','status'=>'25');



foreach ($ArrayB as $key => $valarr) {

    foreach ( $ArrayA as $key2 => $valarr2) {
        $returnArray[] = array_diff_assoc($valarr, $valarr2);
    }
}

echo "<pre>";
print_r($returnArray);
echo "</pre>";

差分をとるからdiffかなと思ったのですが、上記コードの実行結果は下記の通りで、意図とはだいぶ違いました。

Array
(
    [0] => Array
        (
            [flag] => 122
        )

    [1] => Array
        (
            [flag] => 122
        )

    [2] => Array
        (
        )

    [3] => Array
        (
            [flag] => 2
        )

    [4] => Array
        (
            [flag] => 88
        )

    [5] => Array
        (
            [flag] => 88
        )

    [6] => Array
        (
            [flag] => 64
        )

    [7] => Array
        (
        )

)

冒頭に挙げたようなflagとstatusの組み合わせを持つ要素だけを抽出するにはどうしたらいいでしょうか?

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

checkベストアンサー

+4

このように行ってみるのはいかがですか?

<?php
$arr1 = array(
    array(
        "flag" => 2,
        "status" => 25
    ),
    array(
        "flag" => 64,
        "status" => 25
    )
);
$arr2 = array(
    array(
        "flag" => 122,
        "status" => 25
    ),
    array(
        "flag" => 2,
        "status" => 25
    ),
    array(
        "flag" => 64,
        "status" => 25
    ),
    array(
        "flag" => 88,
        "status" => 25
    )
);
$array_diff = array_udiff($arr2, $arr1, function ($array1, $array2) {
    $result1 = $array1['flag'] - $array2['flag'];
    $result2 = $array1['status'] - $array2['status'];
    return $result1 + $result2;
});
print_r($array_diff);

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/01/08 00:00

    ありがとうございます。
    試してみましたが、結果の配列は空でした。
    Array
    (
    )

    キャンセル

  • 2017/01/08 00:24

    失礼しました。修正しました。

    キャンセル

  • 2017/01/08 01:41

    ありがとうございます。
    たしかに目的の結果が得られました!

    しかし自分がアホなため、なぜこのコールバック関数で目的の結果が得られたのか、イマイチ原理というか挙動を理解できておりません。
    もし出来ましたら、仕組みを解説をしていただけましたら幸いです。

    キャンセル

  • 2017/01/08 02:12

    array_diffの比較方法をクロージャで指定できるarray_udiffというものを使っています。クロージャではarr2のflagとarr1のflagで一致する値を取り除き、arr2のstatusとarr1のstatusで一致する値を取り除き残りを変数result1, 2にそれぞれ代入して、それを結合して返しています。

    キャンセル

  • 2017/01/08 02:21 編集

    解説ありがとうございます。
    まだ自分の理解不足でよくわかっていないのですが、その方法ですとflagとstatusをそれぞれ別個に処理しているということですよね。でもそれだと、「flagとstatusの組み合わせ」が崩れたりしませんか?

    たとえば質問文の例ではstatusが全て「25」なので問題にはなりませんが、もしstatusの値が全て異なっていた場合、「flagとstatusの組み合わせ」が維持されないような気が・・・

    キャンセル

  • 2017/01/08 02:25

    すみません、statusの値をいろいろ変えてみて実験してみましたが、きちんと「flagとstatusの組み合わせ」が維持された結果が返ってくるようです。

    でもどうしてあのコールバック関数でそのような挙動になるのか、自分の能力が低すぎて全然理解できません・・・

    キャンセル

  • 2017/01/08 12:05 編集

    このコードは「片方にだけ含まれる組み合わせ」の条件を満たしていません,得られるのは「$arr2のみに含まれる組み合わせ」のみです。またコールバック関数の実装にもバグがあり,例えば$flagと$statusの計算結果がそれぞれ-2と+2のようになったとき,同じと見なされてしまいます。

    キャンセル

  • 2017/01/09 01:47

    >mpywさん

    たしかにそうですね。
    ただ今回のケースでは要素に含まれるのは正の値のみなので、そういう点では問題ないかもしれません。

    キャンセル

+4

PHP7以降ならこう書くのが一番いいです。

<?php

$arr1 = [
    ['flag' => 2, 'status' => 25],
    ['flag' => 64, 'status' => 25],
];
$arr2 = [
    ['flag' => 122, 'status' => 25],
    ['flag' => 2, 'status' => 25],
    ['flag' => 88, 'status' => 25],
];

$compare = function ($x, $y) {
    return $x['flag'] <=> $y['flag'] ?: $x['status'] <=> $y['status'];
};

var_dump(array_merge(
    array_udiff($arr2, $arr1, $compare),
    array_udiff($arr1, $arr2, $compare)
));

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/01/09 02:10

    ありがとうございます。
    php7についての知識がないうえ、コードが難解かつ高度すぎて私には全然読めません。
    知らない記法がいくつかあるし、内容が理解できません・・・

    でもpaizaで実行してみたら、たしかに希望の結果が得られました。

    キャンセル

  • 2017/01/09 11:47

    if ($a < $b) return -1;
    if ($a > $b) return 1;
    return 0;

    これの省略系が

    return $a <=> $b;

    です。また,

    return $a ? $a : $b;

    の省略形が

    return $a ?: $b;

    です。要するに先述のコードは

    「flagで比較して,もし同じだったらstatusでも比較して,それも同じだったら0を返して,array_udiffに等しいと見なさせる。それ以外の場合は-1か1を返して異なると見なさせる。」

    という動作になりますね。この書き方は

    PHP7で宇宙船演算子を使いこなすぞ - Qiita http://qiita.com/Hiraku/items/62821d7d0e7af1ac211e

    で紹介されています。

    キャンセル

+1

これでも一応。

//配列A
$ArrayA[] = array('flag'=>'2','status'=>'25');
$ArrayA[] = array('flag'=>'64','status'=>'25');

//配列B
$ArrayB[] = array('flag'=>'122','status'=>'25');
$ArrayB[] = array('flag'=>'2','status'=>'25');
$ArrayB[] = array('flag'=>'64','status'=>'25');
$ArrayB[] = array('flag'=>'88','status'=>'25');

$returnArray = array_filter( $ArrayB, function( $item ) use( $ArrayA ) {
    $item = json_encode( $item );
    foreach ( $ArrayA as $value ) {
        if ( $item === json_encode( $value ) ) { return false; }
    }
    return true;
} );

echo "<pre>";
print_r($returnArray);
echo "</pre>";
/*
Array
(
    [0] => Array
        (
            [flag] => 122
            [status] => 25
        )

    [3] => Array
        (
            [flag] => 88
            [status] => 25
        )

)
*/

追記:

書き直しました。

$returnArray = array_filter( $ArrayB, function( $item ) use( $ArrayA ) {
    foreach ( $ArrayA as $value ) {
        if ( 0 === count( array_diff( $item, $value ) ) ) { return false; }
    }
    return true;
} );

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/01/08 01:43

    ありがとうございます。
    こちらのご回答に関しても自分の能力不足のため、なぜそのコールバック関数で目的の結果が得られるのか、論理がよく分かりませんでした。
    特にjson_encodeが出てきた辺りがチンプンカンプンです・・・

    キャンセル

  • 2017/01/08 02:26

    array_filter は配列をフィルタリングするための関数で、コールバック関数に配列の要素をそれぞれ1つずつ渡してくれます。

    それを json_encode したものと比較対象の配列の要素を json_encode したものと比較して、同じものがあれば false を返すことでフィルタ(排除)出来ます。

    【[ PHP ] 配列の要素をフィルタリングする ( array_filter ) – 行け!偏差値40プログラマー】
    http://hensa40.cutegirl.jp/archives/1515

    JSONはPHPの配列/オブジェクトを「'{"flag":"122","status":"25"}'」のようなテキストで表現するフォーマットなので配列がどのような形であっても比較しやすいかな、と思って書いてみました。
    すみません、本当は json_encode では順番が保障されていないはずなので上手くいかないこともある可能性があります。(「'{"flag":"122","status":"25"}'」と「'{"status":"25","flag":"122"}'」をテキスト比較しても当然違う)


    キャンセル

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

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

関連した質問

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

  • PHP

    19833questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。