Reputation: 15197
In PHP, the in_array()
function only allows for checking the presence of a single value.
How do I check for multiple values at the same time?
Please provide the answer for both cases:
Upvotes: 160
Views: 192777
Reputation: 48725
Searching the array for multiple values corresponds to the set operations (set difference and intersection), as you will see below.
I also provide usage examples that clearly demonstrate both options.
function in_array_all(array $needles, array $haystack): bool {
return array_diff($needles, $haystack) === [];
}
$animals = ["bear", "tiger", "zebra"];
in_array_all(["bear", "zebra"], $animals); // true, both are animals
in_array_all(["bear", "toaster"], $animals); // false, toaster is not an animal
function in_array_any(array $needles, array $haystack): bool {
return array_intersect($needles, $haystack) !== [];
}
$animals = ["bear", "tiger", "zebra"];
in_array_any(["toaster", "tiger"], $animals); // true, tiger is an amimal
in_array_any(["toaster", "brush"], $animals); // false, no animals here
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 = getAllAnimals();
$all = in_array("tiger", $animals) && in_array("toaster", $animals) && ...
$any = in_array("bear", $animals) || in_array("zebra", $animals) || ...
Upvotes: 245
Reputation: 77044
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
}
Upvotes: 254
Reputation: 514
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);
Upvotes: 2
Reputation: 4948
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.
Upvotes: 2
Reputation: 2393
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!
Upvotes: 3
Reputation: 47619
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
}
Upvotes: 19