46

I have an array containing rows of associative data.

$array1 = array(
    array('ITEM' => 1),
    array('ITEM' => 2),
    array('ITEM' => 3),
);

I have a second array, also containing rows of associative data, that I would like to filter using the first array.

$array2 = array(
    array('ITEM' => 2),
    array('ITEM' => 3),
    array('ITEM' => 1),
    array('ITEM' => 4),
);

This feels like a job for array_diff(), but how can I compare the rows exclusively on the deeper ITEM values?

How can I filter the second array and get the following result?

array(3 => array('ITEM' => 4))
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Jonathan Chan
  • 553
  • 2
  • 7
  • 12

9 Answers9

66

You can define a custom comparison function using array_udiff().

function udiffCompare($a, $b)
{
    return $a['ITEM'] - $b['ITEM'];
}

$arrdiff = array_udiff($arr2, $arr1, 'udiffCompare');
print_r($arrdiff);

Output:

Array
(
    [3] => Array
        (
            [ITEM] => 4
        )
)

This uses and preserves the arrays' existing structure, which I assume you want.

Wiseguy
  • 20,522
  • 8
  • 65
  • 81
  • 7
    I know this is a bit old topic, but for others that use ids that are not integers but strings, you might want to use return strcmp($a['ITEM],$b['ITEM']) in the udiffCompare function – despina Mar 28 '14 at 14:14
  • 18
    In PHP7 and beyond, you can use the [spaceship operator](https://wiki.php.net/rfc/combined-comparison-operator): `return $a['ITEM'] <=> $b['ITEM'];` – bishop Jun 08 '15 at 17:38
  • 1
    One thing I wish I had known before trying to use this function is that the `array_udiff` function arguments `$arr2` and `$arr1` do NOT correlate to the function arguments `$a` and `$b` of `udiffCompare`. I kept scratching my head wondering why elements of `$arr2` were being compared against itself inside of the callback. I found that out with this comment in the php docs: http://php.net/manual/en/function.array-udiff.php#80149 – neuquen Mar 15 '18 at 21:44
20

I would probably iterate through the original arrays and make them 1-dimensional... something like

foreach($array1 as $aV){
    $aTmp1[] = $aV['ITEM'];
}

foreach($array2 as $aV){
    $aTmp2[] = $aV['ITEM'];
}

$new_array = array_diff($aTmp1,$aTmp2);
Jason Fingar
  • 3,358
  • 1
  • 21
  • 27
20

Another fun approach with a json_encode trick (can be usefull if you need to "raw" compare some complex values in the first level array) :

// Compare all values by a json_encode
$diff = array_diff(array_map('json_encode', $array1), array_map('json_encode', $array2));

// Json decode the result
$diff = array_map('json_decode', $diff);
Ifnot
  • 4,914
  • 4
  • 33
  • 47
  • 2
    Thanks, only this works. symmetrical version `public static function myArrayDiff($array1, $array2) { return array_map('json_decode', array_merge( array_diff(array_map('json_encode', $array1), array_map('json_encode', $array2)), array_diff(array_map('json_encode', $array2), array_map('json_encode', $array1)) )); }` – Dimmduh Mar 07 '17 at 11:00
8

A couple of solutions using array_filter that are less performant than the array_udiff solution for large arrays, but which are a little more straightforward and more flexible:

$array1 = [
    ['ITEM' => 1],
    ['ITEM' => 2],
    ['ITEM' => 3],
];

$array2 = [
    ['ITEM' => 2],
    ['ITEM' => 3],
    ['ITEM' => 1],
    ['ITEM' => 4],
];

$arrayDiff = array_filter($array2, function ($element) use ($array1) {
    return !in_array($element, $array1);
});

// OR

$arrayDiff = array_filter($array2, function ($array2Element) use ($array1) {
    foreach ($array1 as $array1Element) {
        if ($array1Element['ITEM'] == $array2Element['ITEM']) {
            return false;
        }
    }
    return true;
});

As always with array_filter, note that array_filter preserves the keys of the original array, so if you want $arrayDiff to be zero-indexed, do $arrayDiff = array_values($arrayDiff); after the array_filter call.

Community
  • 1
  • 1
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
5

you can use below code to get difference

$a1 = Array(
    [0] => Array(
            [ITEM] => 1
        )
    [1] => Array(
            [ITEM] => 2
        )
    [2] => Array(
            [ITEM] => 3
        )
    );

$a2 = Array(
    [0] => Array(
            [ITEM] => 2
        )
    [1] => Array(
            [ITEM] => 3
        )

    [2] => Array(
            [ITEM] => 1
        )
    [3] => Array(
            [ITEM] => 4
        ));

array_diff(array_column($a1, 'ITEM'), array_column($a2, 'ITEM'));
shiyani suresh
  • 778
  • 12
  • 12
1

Having the same problem but my multidimensional array has various keys unlike your "ITEM" consistently in every array.

Solved it with: $result = array_diff_assoc($array2, $array1);

Reference: PHP: array_diff_assoc

AFwcxx
  • 467
  • 1
  • 4
  • 15
0

Another solution if( json_encode($array1) == json_encode($array2) ){ ... }

0

Trust that the maintainers of PHP have optimized array_udiff() to outperform all other techniques which could do the same.

With respect to your scenario, you are seeking a filtering array_diff() that evaluates data within the first level's "value" (the row of data). Within the custom function, the specific column must be isolated for comparison. For a list of all native array_diff() function variations, see this answer.

To use the first array to filter the second array (and output the retained data from the second array), you must write $array2 as the first parameter and $array1 as the second parameter.

array_diff() and array_intersect() functions that leverage (contain u in their function name) expect an integer as their return value. That value is used to preliminary sort the data before actually performing the evaluations -- this is a performance optimization. There may be scenarios where if you only return 0 or 1 (not a three-way comparison), then the results may be unexpected. To ensure a stable result, always provide a comparison function that can return a negative, a positive, and a zero integer.

When comparing integer values, subtraction ($a - $b) will give reliable return values. For greater utility when comparing float values or non-numeric data, you can use the spaceship operator when your PHP version makes it available.

Codes: (Demo)

  • PHP7.4+ (arrow functions)

    var_export(
        array_udiff($array2, $array1, fn($a, $b) => $a['ITEM'] <=> $b['ITEM'])
    );
    
  • PHP7+ (spaceship operator)

    var_export(
        array_udiff(
            $array2,
            $array1,
            function($a, $b) {
                return $a['ITEM'] <=> $b['ITEM'];
            }
        )
    );
    
  • PHP5.3+ (anonymous functions)

    var_export(
        array_udiff(
            $array2,
            $array1,
            function($a, $b) {
                return $a['ITEM'] === $b['ITEM']
                    ? 0
                    : ($a['ITEM'] > $b['ITEM'] ? 1 : -1);
            }
        )
    );
    

Output for all version above:

array (
  3 => 
  array (
    'ITEM' => 4,
  ),
)

When working with object arrays, the technique is the same; only the syntax to access a property is different from accessing an array element ($a['ITEM'] would be $a->ITEM).


For scenarios where the element being isolated from one array does not exist in the other array, you will need to coalesce both $a and $b data to the opposite fallback column because the data from the first array and the second arrays will be represented in both arguments of the callback.

Code: (Demo)

$array1 = array(
    array('ITEM' => 1),
    array('ITEM' => 2),
    array('ITEM' => 3),
);

$array2 = array(
    array('ITEMID' => 2),
    array('ITEMID' => 3),
    array('ITEMID' => 1),
    array('ITEMID' => 4),
);

// PHP7.4+ (arrow functions)
var_export(
    array_udiff(
        $array2,
        $array1,
        fn($a, $b) => ($a['ITEM'] ?? $a['ITEMID']) <=> ($b['ITEM'] ?? $b['ITEMID'])
    )
);
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
-2

Compares array1 against one or more other arrays and returns the values in array1 that are not present in any of the other arrays.

        //Enter your code here, enjoy!

$array1 = array("a" => "green", "red", "blue");
$array2 = array("b" => "green", "yellow", "red");
$result = array_diff($array1, $array2);

print_r($result);
sanyassh
  • 8,100
  • 13
  • 36
  • 70