7

I want to compare the values of two flat, indexed arrays and generate a new array where the keys are the original values from the first array and the values are boolean values indicating whether the same value occurred in both origibal arrays.

$array1 = [
    "car1",
    "car2",
    "car3",
    "car4",
    "car5"
];

$array2 = [
    "car1",
    "car4",
    "car5"
}

I tried to compare the arrays with the array_diff() function but it gave me elements values instead of boolean values.

I want to compare each value from the two arrays and generate an "array map" or maybe using the array_combine() function to get array like this:

[
    "car1" => true,
    "car2" => false,
    "car3" => false
    "car4" => true,
    "car5" => true,
]
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Luqsus
  • 73
  • 1
  • 5

6 Answers6

8

Arrays are fun!

PHP has a TON of array functions, and so there's lots of potential solutions.

I came up with this one as a personal challenge, which uses no loops, filters, or maps.

This solution uses array_intersect to find values that exist in both arrays, then array_values along with array_fill_keys to turn them into associative arrays populated with TRUE or FALSE, and finally array_merge to put them together into a single array:

$array1 = array( 0 => "car1", 1 => "car2", 2 => "car3", 3 => "car4", 4 => "car5");
$array2 = array( 0 => "car1", 1 => "car4", 2 => "car5" );

// Find all values that exist in both arrays
$intersect = array_intersect( $array1, $array2 );
// Turn it into an associative array with TRUE values
$intersect = array_fill_keys( array_values($intersect), TRUE );
// Turn the original array into an associative array with FALSE values
$array1 = array_fill_keys( array_values( $array1 ), FALSE );

// Merge / combine the arrays - $intersect MUST be second so that TRUE values override FALSE values
$results = array_merge( $array1, $intersect );

var_dump( $results ); results in:

array (size=5)
  'car1' => boolean true
  'car2' => boolean false
  'car3' => boolean false
  'car4' => boolean true
  'car5' => boolean true
random_user_name
  • 25,694
  • 7
  • 76
  • 115
4

array_map or array_combine does not actually return what you want. If you wanted to use array_map to the desired effect without writing a foreach loop, below gives you the desired result. Note you have to pass array3 as a reference.

<?php 

$array1 = array( 0 => "car1", 1 => "car2", 2 => "car3", 3 => "car4", 4 => "car5");
$array2 = array( 0 => "car1", 1 => "car4", 2 => "car5" );
$array3 = [];

array_map(function($a) use ($array2, &$array3) {
    $array3[$a] = in_array($a, array_values($array2));
}, $array1);

var_dump($array3);

Output:

array(5) {
  ["car1"]=>
   bool(true)
  ["car2"]=>
   bool(false)
  ["car3"]=>
   bool(false)
  ["car4"]=>
   bool(true)
  ["car5"]=>
   bool(true)
}
Paul Carlton
  • 2,785
  • 2
  • 24
  • 42
  • In my opinion, it is a misuse/abuse of `array_map()` to not use its return value. If you want to iterate an array with a function, but don't want a return value, then use `array_walk()`. – mickmackusa Sep 18 '22 at 01:38
2

This is slow, but it should do what you want, and be easy to understand.

// Loop over the outer array which we're told has all the categories
$result = array();
foreach($array1 as $sCar1) {
  $found = false;

  // Loop over the categories of the post
  foreach($array2 as $sCar2) {

    // If the current post category matches
    // the current category we're searching for
    // note it and move on
    if($sCar2 == $sCar1) {
        $found = true;
        break;
    }
  }

  // Now indicate in the result if the post has the current category
  $result[$sCar1] = $found;
}
quickshiftin
  • 66,362
  • 10
  • 68
  • 89
2
<?php
//EXAMPLE 1

$array1 = [0 => "car1", 1 => "car2", 2 => "car3", 3 => "car4", 4 => "car5"];
$array2 = [0 => "car1", 1 => "car4", 2 => "car5"];
$resultArray = [];

foreach ($array1 as $key => $val) {
    $resultArray[$val] = in_array($val, $array2);
}

var_dump($resultArray);
?>

<?php
//EXAMPLE 2

$array1 = [0 => "car1", 1 => "car2", 2 => "car3", 3 => "car4", 4 => "car5"];
$array2 = [0 => "car1", 1 => "car4", 2 => "car5"];
$resultArray = [];

$flipped = array_flip($array2);

foreach ($array1 as $key => $val) {
    $resultArray[$val] = isset($flipped[$val]);
}


var_dump($resultArray);

?>

RESULT:

array (size=5)
  'car1' => boolean true
  'car2' => boolean false
  'car3' => boolean false
  'car4' => boolean true
  'car5' => boolean true
rrr_2010
  • 87
  • 5
2

With array_count_values it is as simple as this:

$results = array_map(function ($count) {
    return $count !== 1;
}, array_count_values(array_merge($array1, $array2)));

So basically, we merge two arrays together, then count occurrences of values. Then if a count is not equal to 1 we map value to true, and otherwise - false. Interesting, that this will work regardless of which array is shorter.

Here is working demo.

Be aware, that array_count_values function throws E_WARNING for every element which is not string or integer. So this approach will work only on arrays of strings and integers.

Also, this approach might fail if your array elements not unique, for this situation you have to apply array_unique to each array beforehand.

sevavietl
  • 3,762
  • 1
  • 14
  • 21
0

Making iterated in_array() calls or nested loops to make value comparisons is not likely to be the most performant approach because value comparisons are slower than key comparisons in PHP.

Making key comparisons is fast, but making no iterated comparisons will be faster again. By relying on the fact that arrays cannot have duplicate keys on a given level, just alter the elements of each input array to be the desired boolean value and then overwrite the first with the second.

Code: (Demo)

var_export(
    array_replace(
        array_fill_keys($array1, false),
        array_fill_keys($array2, true),
    )
);
mickmackusa
  • 43,625
  • 12
  • 83
  • 136