Nacho
Nacho

Reputation: 23

PHP Compare 2 multidimensional arrays and get non matching items

I'm trying to get non matching items between 2 multidimensional arrays using the 'nombre_entrada', 'precio_productor' and 'id_funcion' to compare. I tried with array_search/array_column but didn't work.

What I need is to get a new array containing the items not matching.

Array 1

Array(
    [0] => Array
        (
            [nombre_entrada] => Entrada General
            [precio_productor] => 250
            [id_funcion] => 907
        )

    [1] => Array
        (
            [nombre_entrada] => Entrada General
            [precio_productor] => 300
            [id_funcion] => 907
        )

    [2] => Array
        (
            [nombre_entrada] => Entrada General
            [precio_productor] => 350
            [id_funcion] => 907
        )
    [3] => Array
        (
            [nombre_entrada] => 2 entradas x
            [precio_productor] => 400
            [id_funcion] => 907
        )

)

Array 2

Array
(
    [0] => Array
        (
            [nombre_entrada] => Entrada General
            [precio_productor] => 350
            [id_funcion] => 907
        )

    [1] => Array
        (
            [nombre_entrada] => 2 entradas x
            [precio_productor] => 400
            [id_funcion] => 907
        )

)

In the Array 1 index 0 and 1 not exists in Array 2 so I need to create a final array including those items.

Final Array

Array(
    [0] => Array
        (
            [nombre_entrada] => Entrada General
            [precio_productor] => 250
            [id_funcion] => 907
        )

    [1] => Array
        (
            [nombre_entrada] => Entrada General
            [precio_productor] => 300
            [id_funcion] => 907
        )
)

Upvotes: 1

Views: 1446

Answers (4)

Will B.
Will B.

Reputation: 18416

You can also use array_filter with !in_array, which accepts an array as the $needle argument. It works similarly to array_udiff($array1, $array2, function($a, $b) { return $a <=> $b; }), but will disregard the array keys, is compatible with PHP 5.3+ and does not need to iterate over the source array with serialize() which would be costly with a very large array.

Example: https://3v4l.org/DdSf1

$array1 = array(
    array
    (
        'nombre_entrada' => 'Entrada General',
        'precio_productor' => 250,
        'id_funcion' => 907,
    ),
    array
    (
        'nombre_entrada' => 'Entrada General',
        'precio_productor' => 300,
        'id_funcion' => 907,
    ),
    array
    (
        'nombre_entrada' => 'Entrada General',
        'precio_productor' => 350,
        'id_funcion' => 907,
    ),
    array
    (
        'nombre_entrada' => '2 entradas x',
        'precio_productor' => 400,
        'id_funcion' => 907,
    )
);
$array2 = array(
    array
    (
        'precio_productor' => 350, //note array key was moved
        'nombre_entrada' => 'Entrada General',
        'id_funcion' => 907,
    ),
    array
    (
        'nombre_entrada' => '2 entradas x',
        'precio_productor' => 400,
        'id_funcion' => 907,
    ),
);
$missing = array_filter($array1, function($v) use ($array2) {
    return !in_array($v, $array2);
});

var_export($missing);

Result:

array (
  0 => 
  array (
    'nombre_entrada' => 'Entrada General',
    'precio_productor' => 250,
    'id_funcion' => 907,
  ),
  1 => 
  array (
    'nombre_entrada' => 'Entrada General',
    'precio_productor' => 300,
    'id_funcion' => 907,
  ),
)

Alternatively If you want to account for the array keys, you can pass true as the third argument to in_array($v, $array2, true), which will cause a strict comparison, which is equivalent to $a <=> $b.


As a simpler solution using serialize, instead of iterating over the array, you can compare the values directly using array_udiff and strcmp. Though I recommend using $a <=> $b (spaceship operator) instead if you have PHP 7.0+

https://3v4l.org/ErtCp

$missing = array_udiff($array1, $array2, function($a, $b) {
    return strcmp(serialize($a), serialize($b));
});

Upvotes: 0

Don&#39;t Panic
Don&#39;t Panic

Reputation: 41810

This is generally the functionality of array_diff.

You can't use array_diff for it directly because it compares the string representation of the array items to find the difference, and arrays don't have a distinct string representation. (They all just convert to "Array".)

PHP can compare arrays though, and if you use array_udiff you can just compare them directly in the comparison function without converting to string.

$result = array_udiff($array1, $array2, function($a, $b) { return $a <=> $b; });

Upvotes: 2

Nacho
Nacho

Reputation: 23

I was able to create the array in this way

$newArray = array();
foreach ($detectadas as $item) {
    if ( 
        array_search($item['nombre_entrada'], array_column($entradasResult2, 'nombre_entrada')) === false OR
        array_search($item['precio_productor'], array_column($entradasResult2, 'precio_productor')) === false OR
        array_search($item['id_funcion'], array_column($entradasResult2, 'id_funcion')) === false
    ) {
        array_push( $newArray, $item );
    }
}

Upvotes: 0

u_mulder
u_mulder

Reputation: 54831

Rather tricky solution, it works only inf you need compare all 3 keys and if order of keys in all subarray are the same:

// first rebuild second array to new array 
// where key is serialized value of value:
$newArray = [];
foreach ($array2 as $item) {
    $newArray[serialize($item)] = $item;
}

// next - filter your first array:
$filteredArray = array_filter(
    $array1,
    function($v) use ($newArray) {
        // here serialize `$v` and check if key 
        // same as serialized `$v` exists in $newArray
        return !isset($newArray[serialize($v)]);
    }
);

Working fiddle https://3v4l.org/aKba9.

Upvotes: 0

Related Questions