Search code examples
phparraysmultidimensional-arrayfilteringarray-difference

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.


Solution

    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.