47

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))
0

9 Answers 9

67

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.

Sign up to request clarification or add additional context in comments.

3 Comments

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
In PHP7 and beyond, you can use the spaceship operator: return $a['ITEM'] <=> $b['ITEM'];
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: php.net/manual/en/function.array-udiff.php#80149
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);

Comments

20

Another fun approach with a json_encode trick (can be useful 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);

2 Comments

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)) )); }
This answer is working much harder than it needs to. Mutating the input with json encoding is not necessary. array_udiff() is the most suitable tool for this task.
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.

Comments

6

You can use below code to get difference.

array_diff(array_column($a1, 'ITEM'), array_column($a2, 'ITEM'));

Comments

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);
            }
        )
    );
    
  • PHP5.0+ (array_udiff added to PHP)

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

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'])
    )
);

Or because only the first column values from both data sets are being compared:

var_export(
    array_udiff($array2, $array1, fn($a, $b) => current($a) <=> current($b))
);

Finally, because both input arrays' rows contain identical structures, you can simply compare whole rows. Demo

var_export(
    array_udiff(
        $array2,
        $array1,
        fn($a, $b) => $a <=> $b
    )
);

Comments

-2

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

1 Comment

This does not work on multidimensional arrays.
-2

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

Comments

-3

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);

1 Comment

This input does not resemble the asked question and this advice is provably incorrect for the asked question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.