I have 2 arrays that look sort of like this:
Array =>
[0] Array( [id]=434b5g6 [unique_id]=banana [level]=8)
[1] Array( [id]=bfrfnr [unique_id]=apple [level]=4)
[2] Array( [id]=yt347509 [unique_id]=grapefruit [level]=9 )
[3] Array( [id]=456645 [unique_id]=strawberry [level]=1)
Array =>
[0] Array( [id]=gon235g6 [unique_id]=strawberry [level]=8 )
[1] Array( [id]=bfrfnr [unique_id]=apple [level]=4 )
[2] Array( [id]=logujtng9 [unique_id]=grapefruit [level]=6 )
[3] Array( [id]=07yburhg [unique_id]=pinapple [level]=1)
I need a way to remove the elements in which the [unique_id] exists in both arrays so that im left with 2 arrays which only contain elements that do not exist in the other. Eg if we were to run the script on these 2 arrays i should be left with:
Array =>
[0] Array( [id]=434b5g6 [unique_id]=banana [level]=8)
Array =>
[0] Array( [id]=07yburhg [unique_id]=pinapple [level]=1)
Im really not sure how to do this though. I know there is array_diff but this only works for single level arrays. Im using a multi level one and only trageting the [unique_id] part of it. Any help would be really appreciated.
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
.
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
Try:
print_r(array_unique($arr1 + $arr2));
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);
}