146

How do I check for multiple values, such as:

$arg = array('foo','bar');

if(in_array('foo','bar',$arg))

That's an example so you understand a bit better, I know it won't work.

daryl
  • 14,307
  • 21
  • 67
  • 92
  • This question does not have a [mcve] because we do not know if only one needle or all needles need to be found in the haystack. This ambiguity leads to divergent answers, confusion, and unwanted page bloat. – mickmackusa May 31 '22 at 22:24

7 Answers7

243

Intersect the targets with the haystack and make sure the intersection count is equal to the target's count:

$haystack = array(...);

$target = array('foo', 'bar');

if(count(array_intersect($haystack, $target)) == count($target)){
    // all of $target is in $haystack
}

Note that you only need to verify the size of the resulting intersection is the same size as the array of target values to say that $haystack is a superset of $target.

To verify that at least one value in $target is also in $haystack, you can do this check:

 if(count(array_intersect($haystack, $target)) > 0){
     // at least one of $target is in $haystack
 }
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Mark Elliot
  • 75,278
  • 22
  • 140
  • 160
  • 13
    this solution is not the best: $needles=array(1,2); $haystack=array(1,1,2,3); return (count(array_intersect($haystack,$needles)) == count($needles)); this will return false, that is not good. Rok Kralj's solution is good for this case. – ihtus Jan 28 '14 at 20:29
  • 3
    I think those array should hold unique data and otherwise this solution won't work – Hashan Mar 30 '19 at 09:07
231

Searching the array for multiple values corresponds to the set operations (set difference and intersection), as you will see below.

In your question, you do not specify which type of array search you want, so I am giving you both options.

ALL needles exist

function in_array_all($needles, $haystack) {
   return empty(array_diff($needles, $haystack));
}

$animals = ["bear", "tiger", "zebra"];
echo in_array_all(["bear", "zebra"], $animals); // true, both are animals
echo in_array_all(["bear", "toaster"], $animals); // false, toaster is not an animal

ANY of the needles exist

function in_array_any($needles, $haystack) {
   return !empty(array_intersect($needles, $haystack));
}

$animals = ["bear", "tiger", "zebra"];
echo in_array_any(["toaster", "tiger"], $animals); // true, tiger is an amimal
echo in_array_any(["toaster", "brush"], $animals); // false, no animals here

Important consideration

If the set of needles you are searching for is small and known upfront, your code might be clearer if you just use the logical chaining of in_array calls, for example:

$animals = ZooAPI.getAllAnimals();
$all = in_array("tiger", $animals) && in_array("toaster", $animals) && ...
$any = in_array("bear", $animals) || in_array("zebra", $animals) || ...
Rok Kralj
  • 46,826
  • 10
  • 71
  • 80
  • 12
    Note: this type of array declaration is >= PHP 5.4 – Claudiu Hojda Mar 10 '14 at 16:23
  • 1
    Excellent solution provided you don't need to perform strict comparison. – faintsignal Jan 03 '17 at 21:46
  • 1
    Don't needlessly use `empty` which *suppresses error reporting* when `!array_diff(..)` will do just fine. – deceze Feb 10 '21 at 10:14
  • Re: intersect method. If $needles, or $haystack is null this is what you get: PHP Warning: array_intersect(): Expected parameter 1 to be an array, null given. in dynamic environment it could happen. Adding before intersect $needles = is_array($needles) ? $needles : []; $haystack = is_array($haystack) ? $haystack : []; allows tis function to finish. – Jeffz Feb 15 '22 at 18:09
19
if(in_array('foo',$arg) && in_array('bar',$arg)){
    //both of them are in $arg
}

if(in_array('foo',$arg) || in_array('bar',$arg)){
    //at least one of them are in $arg
}
RiaD
  • 46,822
  • 11
  • 79
  • 123
10

Going off of @Rok Kralj answer (best IMO) to check if any of needles exist in the haystack, you can use (bool) instead of !! which sometimes can be confusing during code review.

function in_array_any($needles, $haystack) {
   return (bool)array_intersect($needles, $haystack);
}

echo in_array_any( array(3,9), array(5,8,3,1,2) ); // true, since 3 is present
echo in_array_any( array(4,9), array(5,8,3,1,2) ); // false, neither 4 nor 9 is present

https://glot.io/snippets/f7dhw4kmju

sMyles
  • 2,418
  • 1
  • 30
  • 44
  • 13
    This would be more useful as a comment on Rok's answer than as a new answer. – faintsignal Jan 04 '17 at 16:02
  • @Jaymin how so (you provided ZERO details) ... works perfectly fine for me https://glot.io/snippets/f7dhw4kmju – sMyles Dec 07 '18 at 17:47
  • @sMyles I had tried using string value in array instead of integer. You can try once from your side and let me know. – JayminLimbachiya Dec 08 '18 at 05:20
  • @Jaymin still don't have that issue https://glot.io/snippets/f7dhw4kmju – sMyles Dec 08 '18 at 18:52
  • 1
    This *bool* conversion is not suitable here since *array_intersect* returns an array which can be empty or non-empty. @rok-kralj solution is the only preferred one. – codelearner Jan 05 '19 at 14:19
3

IMHO Mark Elliot's solution's best one for this problem. If you need to make more complex comparison operations between array elements AND you're on PHP 5.3, you might also think about something like the following:

<?php

// First Array To Compare
$a1 = array('foo','bar','c');

// Target Array
$b1 = array('foo','bar');


// Evaluation Function - we pass guard and target array
$b=true;
$test = function($x) use (&$b, $b1) {
        if (!in_array($x,$b1)) {
                $b=false;
        }
};


// Actual Test on array (can be repeated with others, but guard 
// needs to be initialized again, due to by reference assignment above)
array_walk($a1, $test);
var_dump($b);

This relies on a closure; comparison function can become much more powerful. Good luck!

maraspin
  • 2,353
  • 20
  • 16
2
if(empty(array_intersect([21,22,23,24], $check_with_this)) {
 print "Not found even a single element";
} else {
 print "Found an element";
}

array_intersect() returns an array containing all the values of array1 that are present in all the arguments. Note that keys are preserved.

Returns an array containing all of the values in array1 whose values exist in all of the parameters.


empty() — Determine whether a variable is empty

Returns FALSE if var exists and has a non-empty, non-zero value. Otherwise returns TRUE.

Umesh Patil
  • 4,668
  • 32
  • 24
2

If you're looking to optimize this search with just a comparison check only I would do:

public function items_in_array($needles, $haystack)
{
    foreach ($needles as $needle) {
        if (!in_array($needle, $haystack)) {
            return false;
        }
    }

    return true;
}

if you're willing to do it ugly doing multiple if(in_array(...&&in_array(... is even faster.

I did a test with 100 and another with 100,000 array elements and between 2 and 15 needles using array_intersect, array_diff, and in_array.

in_array was always significantly faster even when I had to do it 15x for different needles. array_diff was also quite a bit faster than array_intersect.

So if you're just trying to search for a couple of things to see if they exist in an array in_array() is best performance-wise. If you need to know the actual differences/matches then it's probably just easier to use array_diff/array_intersect.

Feel free to let me know if I did my calculations wrong in the ugly example below.

<?php



$n1 = rand(0,100000);
$n2 = rand(0,100000);
$n2 = rand(0,100000);
$n3 = rand(0,100000);
$n4 = rand(0,100000);
$n5 = rand(0,100000);
$n6 = rand(0,100000);
$n7 = rand(0,100000);
$n8 = rand(0,100000);
$n9 = rand(0,100000);
$n10 = rand(0,100000);
$n11 = rand(0,100000);
$n12 = rand(0,100000);
$n13 = rand(0,100000);
$n14 = rand(0,100000);
$n15 = rand(0,100000);
$narr = [$n1, $n2, $n3, $n4, $n5, $n6, $n7, $n8, $n9, $n10, $n11, $n12, $n13, $n14, $n15];

$arr = [];
for($i = 0; $i<100000 ; $i++)
{
    
    $arr[] = rand(0,100000);
    
}


function array_in_array($needles, $haystack)
{
    foreach($needles as $needle)
    {
    
        if (!in_array($needle, $haystack))
            {
                return false;
            }

    }
    
    return true;
}

$start_time = microtime(true);
$failed = true;
if(array_in_array($narr, $arr))
{
    echo "<br>true0<br>";
}

$total_time = microtime(true) - $start_time;
echo "<hr>";
echo($total_time);



$start_time = microtime(true);

if (
    in_array($n1, $arr) !== false &&
    in_array($n2, $arr) !== false &&
    in_array($n3, $arr) !== false &&
    in_array($n4, $arr) !== false &&
    in_array($n5, $arr) !== false &&
    in_array($n6, $arr) !== false &&
    in_array($n7, $arr) !== false &&
    in_array($n8, $arr) !== false &&
    in_array($n9, $arr) !== false &&
    in_array($n10, $arr) !== false &&
    in_array($n11, $arr) !== false &&
    in_array($n12, $arr) !== false &&
    in_array($n13, $arr) !== false &&
    in_array($n14, $arr) !== false &&
    in_array($n15, $arr)!== false) {
    echo "<br>true1<br>";
}

$total_time = microtime(true) - $start_time;
echo "<hr>";
echo($total_time);

$first_time = $total_time;

echo "<hr>";

$start_time = microtime(true);

if (empty($diff = array_diff($narr,$arr)))
{

    echo "<br>true2<br>";
}


$total_time = microtime(true) - $start_time;
echo($total_time);
print_r($diff);
echo "<hr>";

echo "<hr>";
if ($first_time > $total_time)
{
    echo "First time was slower";
}

if ($first_time < $total_time)
{
    echo "First time was faster";
}

echo "<hr>";


$start_time = microtime(true);

if (count(($itrs = array_intersect($narr,$arr))) == count($narr))
{

    echo "<br>true3<br>";
    print_r($result);
}


$total_time = microtime(true) - $start_time;
echo "<hr>";
echo($total_time);

print_r($itrs);

echo "<hr>";

if ($first_time < $total_time)
{
    echo "First time was faster";
}


echo "<hr>";
print_r($narr);
echo "<hr>";
print_r($arr);
Eric
  • 476
  • 2
  • 8
  • 20