redslazer
redslazer

Reputation: 349

Filter out rows from two arrays where the same column value is in both arrays

I have 2 arrays that look like this:

$array1 = [
    ['id' => '434b5g6', 'unique_id' => 'banana', 'level' => 8],
    ['id' => 'bfrfnr', 'unique_id' => 'apple', 'level' => 4],
    ['id' => 'yt347509', 'unique_id' => 'grapefruit', 'level' => 9],
    ['id' => '456645', 'unique_id' => 'strawberry', 'level' => 1],
];

$array2 = [
    ['id' => 'gon235g6', 'unique_id' => 'strawberry', 'level' => 8],
    ['id' => 'bfrfnr', 'unique_id' => 'apple', 'level' => 4],
    ['id' => 'logujtng9', 'unique_id' => 'grapefruit', 'level' => 6],
    ['id' => '07yburhg', 'unique_id' => 'pinapple', 'level' => 1],
];

I need a way to remove the rows containing the same unique_id value in both arrays so that I'm left with 2 arrays which only contain elements that do not exist in the other.

Desired results as two separate arrays:

[['id' => '434b5g6', 'unique_id' => 'banana', 'level' => 8]]

and

[['id' => '07yburhg', 'unique_id' => 'pinapple', 'level' => 1]]

I know there is array_diff(), but this only works for single level arrays. I'm using multi-level arrays and only targeting the unique_id column for comparisons.

Upvotes: 0

Views: 342

Answers (5)

mickmackusa
mickmackusa

Reputation: 47992

array_udiff() will directly return what you need with no data preparation at all.

Declare the columns to be compared in the custom callback function.

Code: (Demo)

// unique in $array1
var_export(array_udiff($array1, $array2, fn($a, $b) => $a['unique_id'] <=> $b['unique_id']));
// unique in $array2
var_export(array_udiff($array2, $array1, fn($a, $b) => $a['unique_id'] <=> $b['unique_id']));

Output:

array (
  0 => 
  array (
    'id' => '434b5g6',
    'unique_id' => 'banana',
    'level' => 8,
  ),
)

array (
  3 => 
  array (
    'id' => '07yburhg',
    'unique_id' => 'pinapple',
    'level' => 1,
  ),
)

Upvotes: 0

deceze
deceze

Reputation: 522382

  1. Get the unique ids out of both arrays.
  2. Calculate their difference (items that are not in both).
  3. Filter the original arrays to items that are in the diff.

Here a sample for PHP 5.3+:

$uniqueIds1 = array_map(function ($item) { return $item['unique_id']; }, $array1);
$uniqueIds2 = array_map(function ($item) { return $item['unique_id']; }, $array2);

$reallyUniqueIds = array_merge(array_diff($uniqueIds1, $uniqueIds2), array_diff($uniqueIds2, $uniqueIds1));

$filteredArray1 = array_filter($array1, function ($item) use ($reallyUniqueIds) {
    return in_array($item['unique_id'], $reallyUniqueIds);
});
$filteredArray2 = array_filter($array2, function ($item) use ($reallyUniqueIds) {
    return in_array($item['unique_id'], $reallyUniqueIds);
});

Explanation:

array_map(function ($item) { return $item['unique_id']; }, $array1)

This just extracts all unique_id values into an array like array('banana', 'apple', ...).

array_merge(array_diff($uniqueIds1, $uniqueIds2), array_diff($uniqueIds2, $uniqueIds1));

This creates the diffs between the arrays both ways and merges them into one array, like:

array('banana', 'apple')
array('strawberry', 'apple')
-> array('banana', 'strawberry')

See array_diff.

Then finally, this goes through the original arrays again to filter out all elements whose unique_key is not in the array we created in the previous step:

array_filter($array1, function ($item) use ($reallyUniqueIds) {
    return in_array($item['unique_id'], $reallyUniqueIds);
})

This just uses a custom callback function for array_filter, which tells it to filter items where in_array($item['unique_id'], $reallyUniqueIds) is false.

Upvotes: 1

hakre
hakre

Reputation: 198116

  1. join all "unique_id" across all arrays.
  2. filter out duplicates to get uniques.
  3. filter all arrays based on the uniques.

The following is a function that operates on one, two or more arrays, first parameter is the key that is to be used for the unique id, any additional one is another array. Usage:

list($unique1, $unique2) = joined_uniquekey('unique_id', $array1, $array2);

Code:

function joined_uniquekey($key, $array1, $array2)
{
    $arrays = func_get_args(); $key = array_shift($arrays);
    $vkey = function($v) use ($key) {return $v[$key];};
    $map = function($f) {return function(array $as) use ($f) {return array_map($f, $as);};};
    $keys = array_count_values(call_user_func_array('array_merge', array_map($map($vkey), $arrays)));
    foreach($keys as $k => $c) if ($c > 1) unset($keys[$k]);
    $hkey = function($v) use ($key, $keys) {return isset($keys[$v[$key]]);};
    $filter = function($f) {return function(array $a) use ($f) {return array_filter($a, $f);};};
    return array_map($filter($hkey), $arrays);
}

Upvotes: 0

Sudhir Bastakoti
Sudhir Bastakoti

Reputation: 100195

Try:


print_r(array_unique($arr1 + $arr2));

Upvotes: 1

maxjackie
maxjackie

Reputation: 23312

foreach ( $array1 as $key1 => $innerarray1 ) {

  foreach ( $array2 as $key2 => $innerarray2 ) {

    if ($innerarray1['unique_id'] == $innerarray2['unique_id']) {

       unset($array2[$key2]);           
 }

}

Now $array2 will have non common unique_id values in it

Upvotes: 0

Related Questions