Question

How to get the difference of arrays containing data-types?

First array:

Array
(
  [0] => Array
  (
    [ID] => 21323154
    [NAME] => Name_2
    [PREVIEW_TEXT] => Text_2
  )
)

Second array:

Array
(
  [0] => Array
  (
    [ID] => 543547564
    [NAME] => Name_1
    [PREVIEW_TEXT] => Text_1
  )
  [1] => Array
  (
    [ID] => 222213322
    [NAME] => Name_2
    [PREVIEW_TEXT] => Text_2
  )
  [2] => Array
  (
    [ID] => 333876833
    [NAME] => Name_3
    [PREVIEW_TEXT] => Text_3
  )
)

The result should be an array:

Array
(
  [0] => Array
  (
    [ID] => 543547564
    [NAME] => Name_1
    [PREVIEW_TEXT] => Text_1
  )
  [1] => Array
  (
    [ID] => 333876833
    [NAME] => Name_3
    [PREVIEW_TEXT] => Text_3
  )
)

I tried different options, but they all return the result found the difference, i.e. the first array.

I have a different ID

Was it helpful?

Solution

Just try with:

$output = array_udiff($arraySecond, $arrayFirst, function($a, $b){
    return strcmp($a['NAME'], $b['NAME']);;
});

Output:

array(2) {
  [0] =>
  array(3) {
    'ID' =>
    int(543547564)
    'NAME' =>
    string(6) "Name_1"
    'PREVIEW_TEXT' =>
    string(6) "Text_1"
  }
  [2] =>
  array(3) {
    'ID' =>
    int(333876833)
    'NAME' =>
    string(6) "Name_3"
    'PREVIEW_TEXT' =>
    string(6) "Text_3"
  }
}

OTHER TIPS

If both arrays are large, array_diff will be very inefficient, because it compares each element of the first array with each element of the second. A faster solution is to split the process into two steps: first, generate a set of keys to remove:

 $remove = array();
 foreach($firstArray as $item)
      $remove[$item['name']] = 1;

and then iterate over the second array and add "good" items to the result:

 $result = array(); 
 foreach($secondArray as $item)
      if(!isset($remove[$item['name']]))
           $result []= $item;

This will give you linear performance, while array_diff is quadratic.

Diff both arrays against the field (column) you want to, give back only those entries then (thanks to keys):

$col  = 'NAME';
$diff = array_intersect_key($b, array_diff(array_column($b, $col), array_column($a, $col)));
print_r($diff);

If you prefer to have this less quadratic but linear, you can also solve it via iteration (inspired by georg's answer but using array_column() again):

$filtered = function ($col, $a, $b) {
    return iterator_to_array(call_user_func(function () use ($col, $a, $b) {
        $coled = array_flip(array_column($a, $col));
        foreach ($b as $bk => $bv) if (!isset($coled[$bv[$col]])) yield $bk => $bv;
    }));
};

print_r($filtered('NAME', $a, $b));

With $a and $b as outlined, you will get the following result for both examples:

Array
(
    [0] => Array
        (
            [ID] => 543547564
            [NAME] => Name_1
            [PREVIEW_TEXT] => Text_1
        )

    [2] => Array
        (
            [ID] => 333876833
            [NAME] => Name_3
            [PREVIEW_TEXT] => Text_3
        )

)

// 1.) - diff against column, intersect keys
$filtered = function($col, $a, $b) {
    return array_intersect_key($b, array_diff(array_column($b, $col), array_column($a, $col)));
};

// 2.) - iterate and take only unset by column
$filtered = function ($col, $a, $b) {
    return iterator_to_array(call_user_func(function () use ($col, $a, $b) {
        $coled = array_flip(array_column($a, $col));
        foreach ($b as $bk => $bv) if (!isset($coled[$bv[$col]])) yield $bk => $bv;
    }));
};

// 3.) - array_udiff against column
$filtered = function($col, $a, $b) {
    return array_udiff($b, $a, function ($a, $b) use ($col) {
        return strcmp($a[$col], $b[$col]);
    });
};

Usage:

print_r($filtered('NAME', $a, $b));

Where $a is the array containing the elements to remove from the $b array. So $a is the first array of the question and $b is the second array of the question.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top