PHP array comparison operator not working as expected - php

I have to arrays and want to check if they have the same values, not matters the order, so I used == operator:
$roles = ['admin', 'manager'];
$needle = ['manager', 'admin'];
$needle == $roles; // false
The problem is that with same values but in different order, the operator evaluates the comparison to false.
How to properly compare two arrays to check if values are the same?
UPDATE
For now, I'm going with array_intersect:
$hasExactRoles = (
(array_intersect($roles, $needle) === $roles) &&
(array_intersect($needle, $roles) === $needle)
);

You can check what is a difference between arrays.
$roles = ['admin', 'manager'];
$needle = ['manager', 'admin'];
if (empty(array_diff($roles, $needle))) {
echo 'The same.';
}
The correct answer is:
$roles = ['admin', 'manager'];
$needle = ['manager', 'admin'];
sort($roles);
sort($needle);
if ($roles === $needle) {
echo 'The same.';
}

== with arrays evaluates to true if $a and $b have the same key/value pairs. In your example, the numeric keys 0 and 1 match up with different values, so the comparison fails.
As other people have mentioned, you can use array_diff to compare just the values, e.g.
if (count(array_diff($needle, $roles)) > 0) {
// Arrays are not identical
}
but note that array_diff only works in one direction - it returns the values from the first argument that are not present in the second, so you might also need to run it with the arguments in reverse order, depending on your exact scenario.
As #axiac mentions in the comment, this still won't cover situations where elements can occur multiple times. If this applies then there are probably better ways that you can approach this, e.g. by sorting the arrays or making use of functions like array_intersect.

Use the array_diff function to return any values from the second array that are not in the first. If array_diff is empty then the arrays are the same:
$roles = ['admin', 'manager'];
$needle = ['manager', 'admin'];
$result = array_diff($roles, $needle);
if (empty($result)) {
// Arrays are the same
}

Related

how to differ 0 from FALSE when using in_array

i have a function to filter unwanted values in array (usually false and empty values) here it is :
function filter_array($arr , $filter = array('' , FALSE)){
foreach($arr as $k=>$v)
{
if(in_array(trim($v) , $filter))
unset($arr[$k]);
}
return $arr;
}
here is the problem , it considering 0 as false and removing them from array ... how can i fix this ?
one way is to loop trough $filter and and use === to check the values but i want to avoid another loop
in_array takes a third optional argument for strict comparison.
in_array(trim($v) , $filter, true)

PHP How to get a boolean average of an array

EDIT2: This goes to the top for a reason. This question is asked wrong, but I won´t change the title, since maybe other people are caught in this misstake. I am NOT looking for an "average" - I merely want to exit with the first "false" in an array.
My though to this questions were quite twisted - therefore I asked the wrong question.
Anyway: As stated, I won´t change the question itself.
What I want to do is basically calculate something like a boolean average of an array. I know about booleans and that they are not meant to be something with an average, but please read on to see what I am doing.
My array looks like this:
$array = array(
true,
false,
true,
true
);
I now want to get an AND-operation done on this array to see, if everything in there is true or if a subfunction returned false. This is basically a list of results from different subfunctions.
This specific example then should return false, because $array[1] is false.
EDIT:
What I am looking for is a builtin PHP-function which seems not to exists. A custom implementation has the advantage to exit the iteration over this array in comparison to in_array() which might not do this.
Can you help me out, stackoverflow?
Try in_array:
$array = array(
true,
false,
true,
true
);
echo in_array(false, $array);
If one of the elements is false, it will return false otherwise it returns true.
Update: in_array, returns out of the loop as soon as the searched value is matched. The worst case I suppose is when you have a single false at the end of the searched array. The linked source are for PHP 5.3.
As far as strict checking is concerned, you can do so passing in the third parameter to in_array:
echo in_array(false, $array, true);
Come on, it would appear you didn't even try:
function checkArray(array $in)
{
foreach ($in as $bool)
{
if (!$bool)//replace with type&value checking if that's what you're after
return false;
}
return true;
}
var_dump(checkArray(array(true, false, true, true)));//false
var_dump(checkArray(array(true, true)));//true
There are, of course, a bunch of alternative ways to do what you want/need, depending on what the actual data will look like. If it's all booleans:
if (array_sum($array) != count($array))
{//true == 1, array_sum(array(true, true)) == count(array(true, true)) == 2
echo 'array contains false, or non-boolean values, like 123';
}
//for a real average:
$avg = round(array_sum($array)/count($array));
The latter will yield 1 if 50%>= of the values in the array are true, and 0 otherwise. It's then a simple matter of casting that value to a boolean to get the "average bool value":
$avg = (bool) round(
array_sum($array)/count($array)
);
or, for example:
$valsAsKey = array_flip(
array_map(
'intval',//make ints
$array
)
);
if (isset($valsAsKey[0]))
{//(int) false === 0
echo 'False in array';
}
Though these approaches don't use iteration explicitly, they do iterate the array data implicitly. A quick test did show that the simple foreach outperformed the other approaches here.
I have tried around a lot, until i came to this final result.
This is my code:
<?php
$array = array();
$array[] = true;
$array[] = false;
$array[] = false;
$array[] = true;
$array[] = false;
var_dump($array);
if((count($array)/2) <= array_sum($array)){
echo "true";
// return true
} else {
echo "false";
// return false
}
?>
it counts the elements of the array, and compares it with the COUNTED trues (array_sum($array)). Then it returns true or false, dependent on result.
You could iterate through the array and set a result to false if any vals are false;
$result = true;
foreach ($array as $v) {
if ($v===false) $result = false;
}
You can use array_filter without callback. In this case all entries of array equal to false will be removed.
if (count(array_filter($array)) == count($array)) echo 'TRUE';

Check if all values in array are the same

I need to check if all values in an array equal the same thing.
For example:
$allValues = array(
'true',
'true',
'true',
);
If every value in the array equals 'true' then I want to echo 'all true'. If any value in the array equals 'false' then I want to echo 'some false'
Any idea on how I can do this?
All values equal the test value:
// note, "count(array_flip($allvalues))" is a tricky but very fast way to count the unique values.
// "end($allvalues)" is a way to get an arbitrary value from an array without needing to know a valid array key. For example, assuming $allvalues[0] exists may not be true.
if (count(array_flip($allvalues)) === 1 && end($allvalues) === 'true') {
}
or just test for the existence of the thing you don't want:
if (in_array('false', $allvalues, true)) {
}
Prefer the latter method if you're sure that there's only 2 possible values that could be in the array, as it's much more efficient. But if in doubt, a slow program is better than an incorrect program, so use the first method.
If you can't use the second method, your array is very large, and the contents of the array is likely to have more than 1 value (especially if the 2nd value is likely to occur near the beginning of the array), it may be much faster to do the following:
/**
* Checks if an array contains at most 1 distinct value.
* Optionally, restrict what the 1 distinct value is permitted to be via
* a user supplied testValue.
*
* #param array $arr - Array to check
* #param null $testValue - Optional value to restrict which distinct value the array is permitted to contain.
* #return bool - false if the array contains more than 1 distinct value, or contains a value other than your supplied testValue.
* #assert isHomogenous([]) === true
* #assert isHomogenous([], 2) === true
* #assert isHomogenous([2]) === true
* #assert isHomogenous([2, 3]) === false
* #assert isHomogenous([2, 2]) === true
* #assert isHomogenous([2, 2], 2) === true
* #assert isHomogenous([2, 2], 3) === false
* #assert isHomogenous([2, 3], 3) === false
* #assert isHomogenous([null, null], null) === true
*/
function isHomogenous(array $arr, $testValue = null) {
// If they did not pass the 2nd func argument, then we will use an arbitrary value in the $arr (that happens to be the first value).
// By using func_num_args() to test for this, we can properly support testing for an array filled with nulls, if desired.
// ie isHomogenous([null, null], null) === true
$testValue = func_num_args() > 1 ? $testValue : reset($arr);
foreach ($arr as $val) {
if ($testValue !== $val) {
return false;
}
}
return true;
}
Note: Some answers interpret the original question as (1) how to check if all values are the same, while others interpreted it as (2) how to check if all values are the same and make sure that value equals the test value. The solution you choose should be mindful of that detail.
My first 2 solutions answered #2. My isHomogenous() function answers #1, or #2 if you pass it the 2nd arg.
Why not just compare count after calling array_unique()?
To check if all elements in an array are the same, should be as simple as:
$allValuesAreTheSame = (count(array_unique($allValues, SORT_REGULAR)) === 1);
This should work regardless of the type of values in the array.
Update: Added the SORT_REGULAR flag to avoid implicit type-casting as pointed out by Yann Chabot
Also, you can condense goat's answer in the event it's not a binary:
if (count(array_unique($allvalues)) === 1 && end($allvalues) === 'true') {
// ...
}
to
if (array_unique($allvalues) === array('foobar')) {
// all values in array are "foobar"
}
If your array contains actual booleans (or ints) instead of strings, you could use array_sum:
$allvalues = array(TRUE, TRUE, TRUE);
if(array_sum($allvalues) == count($allvalues)) {
echo 'all true';
} else {
echo 'some false';
}
http://codepad.org/FIgomd9X
This works because TRUE will be evaluated as 1, and FALSE as 0.
You can compare min and max... not the fastest way ;p
$homogenous = ( min($array) === max($array) );
$alltrue = 1;
foreach($array as $item) {
if($item!='true') { $alltrue = 0; }
}
if($alltrue) { echo("all true."); }
else { echo("some false."); }
Technically this doesn't test for "some false," it tests for "not all true." But it sounds like you're pretty sure that the only values you'll get are 'true' and 'false'.
Another option:
function same($arr) {
return $arr === array_filter($arr, function ($element) use ($arr) {
return ($element === $arr[0]);
});
}
Usage:
same(array(true, true, true)); // => true
Answering my method for people searching in 2023.
$arr = [5,5,5,5,5];
$flag = 0;
$firstElement = $arr[0];
foreach($arr as $val){
// CHECK IF THE FIRST ELEMENT DIFFERS FROM ANY OTHER ELEMENT IN THE ARRAY
if($firstElement != $val){
// FIRST MISMATCH FOUND. UPDATE FLAG VALUE AND BREAK OUT OF THE LOOP.
$flag = 1;
break;
}
}
if($flag == 0){
// ALL THE ELEMENTS ARE SAME... DO SOMETHING
}else{
// ALL THE ELEMENTS ARE NOT SAME... DO SOMETHING
}
In an array where all elements are same, it should always be true that all the elements MUST match with the first element of the array. Keeping this logic in mind, we can get the first element of the array and iterate through each element in the array to check for that first element in the loop which does not match with the first element in the array. If found, we will change the flag value and break out of the loop immediately. Else, the loop will continue till it reaches the end. Later, outside the loop, we can use this flag value to determine if all the elements in the array are same or not.
This solution is good for arrays with definite limit of elements (small array). However, I am not sure how good this solution would be for arrays with very large number of elements present considering that we are looping through each and every element to check for the first break even point. Please use this solution at your own convenience and judgement.
$x = 0;
foreach ($allvalues as $a) {
if ($a != $checkvalue) {
$x = 1;
}
}
//then check against $x
if ($x != 0) {
//not all values are the same
}

PHP Search Array Question

I need to have an array_search search my array strictly making sure that the item is identical (meaning the whole thing is the same thing as the input value). I know about the third variable in a array_search() function in PHP - the Strict one, but I don't want it to check if its the same instance, as it is not. How would I do this?
Here is the code I'm currently using:
array_search(some, array(someItem,anothervariable, yetanothervariable, some));
//output - 0 (the first item) which contains some but isn't exactly some.
Requested output:
Instead of outputting the first item that contains some, someItem, it would output the key for the last item, 3, that is the exact search value.
Array search with strict is equivalent to the === operator.
Array search without strict is equivalent to the == operator.
If you need some sort of special comparison that isn't covered by either of them (comparing elements of objects for example) then you need to write a loop.
Are you open to using a foreach loop instead of array_search?
If so try this:
$haystack = array('something', 'someone', 'somewhere', 'some');
$needle = 'some';
foreach($haystack as $key=>$straw){
if($straw === $needle){
$straws[$key] = $straw;
}
}
print_r($straws);
it will print
Array ( [3] => some )
Or you could use array_keys() with the search value specified.
Then, using the same $haystack and $needle above:
$result = array_keys($haystack,$needle,TRUE);
print_r($result);
This returns:
Array ( [0] => 3 )
The first argument is the array to return keys from, The second arg is the search value, if you include this arg, then only keys from array elements that match the search value are returned. Including the third boolean arg tells the function to use match type as well (===).
Not really sure what you are asking but in PHP strict comparison is achieved with the
triple equal sign (===). This means that both the value and the type must be the same.
So if you compare a string "1" and an integer 1 with === it will fail.
If strict is false then comparing string "1" with integer 1 would succeed.
This is the meaning of strict in the array_search case.
I implemented array_search below so you can see what it is doing.
function my_array_search($input, $search_array, $strict=false) {
if(is_array($search_array)) {
foreach($search_array as $key => $val) {
if($strict === true) {
if($val === $input) {
return $key;
}
} else {
if($val == $input) {
return $key;
}
}
}
}
}

PHP: Built-in function to check whether two Array values are equal ( Ignoring the order)

Is there a built-in function for PHP for me to check whether two arrays contain the same values ( order not important?).
For example, I want a function that returns me true for the following two inputs:
array('4','5','2')
array('2','4','5')
Edit: I could have sorted the two arrays and compare them, but as I am such a lazy guy, I would still prefer a one-liner that I can pull out and use.
array_diff looks like an option:
function array_equal($a1, $a2) {
return !array_diff($a1, $a2) && !array_diff($a2, $a1);
}
or as an oneliner in your code:
if(!array_diff($a1, $a2) && !array_diff($a2, $a1)) doSomething();
The best solution is to sort both array and then compare them:
$a = array('4','5','2');
$b = array('2','4','5');
sort($a);
sort($b);
var_dump($a === $b);
As a function:
function array_equal($a, $b, $strict=false) {
if (count($a) !== count($b)) {
return false;
}
sort($a);
sort($b);
return ($strict && $a === $b) || $a == $b;
}
Here’s another algorithm looking for each element of A if it’s in B:
function array_equal($a, $b, $strict=false) {
if (count($a) !== count($b)) {
return false;
}
foreach ($a as $val) {
$key = array_search($val, $b, $strict);
if ($key === false) {
return false;
}
unset($b[$key]);
}
return true;
}
But that has a complexity of O(n^2). So you better use the sorting method.
The array_diff() method above won't work.
php.net's manual says that array_diff() does this:
"Returns an array containing all the entries from array1 that are not present in any of the other arrays."
So the actual array_diff() method would be:
function array_equal($array1, $array2)
{
$diff1 = array_diff($array1, $array2);
$diff2 = array_diff($array2, $array1);
return
(
(count($diff1) === 0) &&
(count($diff2) === 0)
);
}
However I go with the sort method :D
You can use array_diff.
$a = array('4','5','2');
$b = array('2','4','5');
if(count(array_diff($a, $b)) == 0) {
// arrays contain the same elements
} else {
// arrays contain different elements
}
However, a problem with this approach is that arrays can contain duplicate elements, and still match.
You can use array_intersect() instead of array_diff():
$a = array('4','5','2');
$b = array('2','4','5');
$ca = count($a);
$cb = count($b);
$array_equal = ( $ca == $cb && $ca == count(array_intersect($a, $b)) );
Performance wise. solution, where two factors are important:
the more often arrays are matching, the more array_intersect() is fast.
the more arrays are big (more than 10 values), the more array_intersect() is fast.
Depending on these factors, one method can be two or three time faster than the other. For big arrays with few (or no) matching combinations, or for little arrays with lots of matching, both methods are equivalent.
However, the sort method is always faster, except in the case with little arrays with few or no matching combinations. In this case the array_diff() method is 30% faster.
You only need to compare one-way using array_diff() and use count() for the inverted relationship.
if (count($a1) == count($a2) && !array_diff($a1, $a2)) {
// equal arrays
}
If the arrays being compared consist of only strings and/or integers, array_count_values allows you to compare the arrays quickly (in O(n) time vs O(n log n) for sorting) by verifying that both arrays contain the same values and that each value occurs the same # of times in both arrays.
if(array_count_values($a1) == array_count_values($a2)) {
//arrays are equal
}
As an addition to the accepted reply from #knittl
To cover the case, when one of the arrays has additional members:
function areEqualIfOrderIgnored(array $a1, array $a2): bool
{
if (
! array_diff($a1, $a2)
&& ! array_diff($a2, $a1)
&& count($a1) === count($a2)
) {
return true;
}
return false;
}
Or one line, as requested (but not nice)
if (! array_diff($a1, $a2) && ! array_diff($a2, $a1) && count($a1) === count($a2)) {do smth}

Categories