Arrays7 min readExamples run on PHP 8.5.10

array_udiff_assoc()

Learn how array_udiff_assoc() finds entries in one array that have no matching key and value elsewhere, using your own callback to compare values.

Signature

array_udiff_assoc(array $array, array ...$arrays, callable $value_compare_func): array

Purpose

array_udiff_assoc() computes a difference between arrays, and it asks two questions about each entry of the first array: does another array have the same key, and does the value stored under that key count as equal? The key check is done by PHP itself. The value check is done by a callback that you supply. An entry is kept only if no other array has a matching key with a value your callback treats as equal.

This suits data that plain === or string comparison cannot judge well: case-insensitive text, records compared by one field, or numbers compared with a tolerance you define.

Signature

Parameters and defaults

  • $array: the array whose entries you want to filter. Nothing else is returned.
  • ...$arrays: one or more arrays to compare against. Their extra entries never appear in the result.
  • $value_compare_func: the last argument, a callable with the shape function (mixed $a, mixed $b): int. It must return a value below zero, zero, or above zero. Zero means "equal".

There are no default values. The callback is required and must come after all the arrays.

Return value and failures

The function returns a new array containing the entries from the first array that are not matched in any other array. Keys from the first array are preserved, so the result may not be a list. If everything is matched, you get an empty array.

Passing something that is not an array, or a value that is not callable, throws a TypeError. Your callback may also throw, and that exception propagates to the caller.

Example 1: case-insensitive values

Here strcasecmp is the callback. Key a exists in both arrays and Apple equals apple ignoring case, so it is removed. Key b matches but the values differ. Key c has no counterpart in the second array, because the other array uses d.

Example
<?php
$expected = ['a' => 'Apple', 'b' => 'Banana', 'c' => 'Cherry'];
$actual = ['a' => 'apple', 'b' => 'Blueberry', 'd' => 'cherry'];
$diff = array_udiff_assoc($expected, $actual, 'strcasecmp');
echo json_encode($diff, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"b":"Banana","c":"Cherry"}

Example 2: the extra key check

The sibling function array_udiff() ignores keys. With the same values in a different order, it reports no difference, while array_udiff_assoc() sees that positions 0 and 1 hold different values.

Example
<?php
$left = [10, 20, 30];
$right = [20, 10, 30];
$compare = fn(int $x, int $y): int => $x <=> $y;
echo json_encode(array_udiff($left, $right, $compare), JSON_FORCE_OBJECT), "\n";
echo json_encode(array_udiff_assoc($left, $right, $compare), JSON_FORCE_OBJECT), "\n";
Output
{}
{"0":10,"1":20}

Example 3: records and several arrays

Values can be arrays too. This callback compares stock records by their qty field. With several comparison arrays, an entry is dropped when it is matched in at least one of them.

Example
<?php
$byQty = fn(array $x, array $y): int => $x['qty'] <=> $y['qty'];
$base = ['apple' => ['qty' => 3], 'pear' => ['qty' => 5], 'plum' => ['qty' => 7]];
$northStock = ['apple' => ['qty' => 3], 'pear' => ['qty' => 6]];
$southStock = ['plum' => ['qty' => 7]];
echo json_encode(array_udiff_assoc($base, $northStock, $southStock, $byQty), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"pear":{"qty":5}}

Edge cases

  • Only the first array is filtered. Entries that exist only in the other arrays are ignored.
  • One dimension only. Nested arrays are not compared recursively unless your callback does it.
  • Keys come from PHP, not your callback. Numeric-string keys such as "1" are already stored as integer keys, so they match 1. The callback cannot make two different keys match.
  • The callback may see any pair of values. PHP sorts each array internally before comparing, so the callback must handle every value from every array in any order. A callback that assumes the first argument always comes from the first array is unreliable.
  • Float results are truncated. The return value is cast to an integer, so 0.5 becomes 0 and counts as equal. Prefer <=> over subtraction.

Common mistakes

  1. Returning a boolean. A callback like fn($a, $b) => $a == $b returns true for equal values, which is 1, meaning "greater". Equal values should return 0.
  2. Expecting a symmetric result. array_udiff_assoc($a, $b, $f) and array_udiff_assoc($b, $a, $f) usually differ. Run it both ways if you need both sides.
  3. Using it when keys do not matter. If positions are irrelevant, use array_udiff(). Otherwise reordered lists will look different.
  4. Putting the callback first. Unlike array_filter(), the callback is the last argument.
  5. Writing an inconsistent comparison. A callback that does not behave like a proper ordering can give surprising results because of the internal sorting.
  • array_diff() and array_diff_assoc(): the built-in comparison versions.
  • array_udiff(): callback for values, keys ignored.
  • array_diff_uassoc(): callback for keys, built-in comparison for values.
  • array_udiff_uassoc(): separate callbacks for values and keys.
  • array_uintersect_assoc(): the intersection counterpart.

Recap

Use array_udiff_assoc() when an entry should count as present only if both its key and a value judged by your callback match. The callback returns an integer with zero meaning equal, the result keeps the first array's keys, and only the first array is filtered.

Tested examples

Case-insensitive value comparison with key check
<?php
$expected = ['a' => 'Apple', 'b' => 'Banana', 'c' => 'Cherry'];
$actual = ['a' => 'apple', 'b' => 'Blueberry', 'd' => 'cherry'];
$diff = array_udiff_assoc($expected, $actual, 'strcasecmp');
echo json_encode($diff, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"b":"Banana","c":"Cherry"}
array_udiff() versus array_udiff_assoc()
<?php
$left = [10, 20, 30];
$right = [20, 10, 30];
$compare = fn(int $x, int $y): int => $x <=> $y;
echo json_encode(array_udiff($left, $right, $compare), JSON_FORCE_OBJECT), "\n";
echo json_encode(array_udiff_assoc($left, $right, $compare), JSON_FORCE_OBJECT), "\n";
Output
{}
{"0":10,"1":20}
Comparing records by a field across several arrays
<?php
$byQty = fn(array $x, array $y): int => $x['qty'] <=> $y['qty'];
$base = ['apple' => ['qty' => 3], 'pear' => ['qty' => 5], 'plum' => ['qty' => 7]];
$northStock = ['apple' => ['qty' => 3], 'pear' => ['qty' => 6]];
$southStock = ['plum' => ['qty' => 7]];
echo json_encode(array_udiff_assoc($base, $northStock, $southStock, $byQty), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"pear":{"qty":5}}