Check if all values in array are the same - php

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
}

Related

Why array_shift on an array with an empty string breaks the loop?

I just noticed that iterating an array using a while and array_shift behaves differently from a simple for loop when encounters an empty string. Here's a sample:
While loop:
$arr=[1, "",1,""];
while ($elm = array_shift($arr))
{
var_dump($elm);
}
For loop:
$arr=[1, "",1,""];
for ($i = 0; $i<count($arr); $i++)
{
var_dump($arr[$i]);
}
die();
Why does the while exit the loop?
Because an empty string is a falsy value in PHP:
var_dump((bool) ""); // bool(false)
The PHP Manual
To make the first example work with empty strings you should check against array_shift returning NULL:
$arr = [1, "", 1, ""];
while (($elm = array_shift($arr)) !== NULL) {
var_dump($elm);
}
Explanation
array_shift removes the first element from the array and returns its value:
$arr = [1, ""];
array_shift($arr); // we get 1
array_shift($arr); // we get ""
array_shift($arr); // we get NULL because the array is empty now
In your first example you have while ($elm = array_shift($arr)) which means:
remove the first element and save its value inside $elm
interpret $elm as a boolean (this is done implicitly) and only continue if it evaluates to TRUE.
Let's manually go through each iteration to make it more clear:
first iteration: while ($elm = 1) -> while (true) because 1 is truthy. We continue the loop.
second iteration: while ($elm = "") -> while (false) because an empty string is falsy. We exit the loop.
Because the empty string evaluates to false
Because the second value of your array is empty string which converts to bool false
Try to use another array and everything will be good:
$arr=[1, "non-empty value", 1, "another non-empty value"];
while ($elm = array_shift($arr))
{
var_dump($elm);
echo '<br>'; // this is bonus ;)
}
The solutions proposed by others are still prone to error if an array contains a null. If it's really necessary to modify the array rather than do a simple foreach, a robust way to construct this would be:
while ($arr)
{
$elm = array_shift($arr)
var_dump($elm);
}
This is because arrays are always truthy unless they're empty, regardless of what values they contain.

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';

What is a shorthand way for checking that multiple variables are ALL equal to the same value in an IF statement? (PHP)

Is there a shorthand way of writing the code below?
if (($tstat=='no_prices')&&($l1stat=='no_prices')&&($l2stat=='no_prices')&&($l3stat=='no_prices'))
{
//do something
}
I tried using the below code,but it did something when one of the variables was not equal to 'no_prices'.
if (($tstat && $l1stat && $l2stat && $l3stat)=='no_prices')
{
//do something
}
To check that the strings weren't causing problems I tried substituting 0 for 'no_prices' and 1 for other values, but the result was the same.
array_flip is several times faster than array_unique:
function all_equal($arr, $value) {
return array_keys(array_flip($arr)) == array($value);
}
$arr = array($tstat, $l1stat, $l2stat, $l3stat);
echo all_equal($arr, 'no_prices');
A quick profile for the answers given thus far, for 1000 iterations on array length 1000:
array_flip: 0.07321620 seconds
array_unique: 0.32569408 seconds
foreach: 0.15136194 seconds
array_filter: 0.41404295 seconds
The code used to profile is here: http://codepad.org/szgNfWHe
Note: As #cypherabe rightly points out, array_flip does not overtake array_unique until the array has at least 5 elements, and does not overtake foreach until the array has at least 10 elements.
Unless I'm mistaken, there's no native way of doing this. If this is something that you have to check for often, try using a custom function for it, e.g.:
function allEquals($chkstr, $vals) {
if (!is_array($vals)) { die('allEquals() $vals not an array'); }
foreach ($vals AS $v) {
if ($chkstr != $v) { return false; }
}
return true;
}
My first idea would go into PHP's Array API:
// $tstadt, $l1stat, … are all "no_prices"
$isAllNoPrice = array_unique(array($tstat, $l1stat, …)) == array("no_prices"));
if ($isAllNoPrice) {
// …
}
Documentation is mandatory otherwise nobody (including yourself) will understand the code.
If efficiency might be a concern others pointed out that array_unique() seems to be slow. Using the keys of the hash table would be a next approach:
// $tstadt, $l1stat, … are all "no_prices"
$varsMap = array(
$tstat => null,
$l1stat => null,
// …
);
if (array_keys($varsMap) == array("no_prices")) {
// …
}
But now the wall of code is growing. PHP offers one operator which nearly does what you want and is chainable: &
$v1 = "no_prices";
$v2 = "no_prices";
$v3 = "no_prices";
var_dump(($v1 & $v2 & $v3) == "no_prices"); // bool(true)
$v3 = "prices";
var_dump(($v1 & $v2 & $v3) == "no_prices"); // bool(false)
I said it nearly does what you want: There are cases in which you will have false positives:
$v1 = 1;
$v2 = 1;
$v3 = 3;
var_dump(($v1 & $v2 & $v3) == 1); // bool(true)
For Strings it seems to cut the bitmask to the shortest string:
$v1 = "abcd";
$v2 = "ab";
$v3 = "abc";
var_dump($v1 & $v2 & $v3); // "ab"
var_dump(($v1 & $v2 & $v3) == "ab"); // bool(true)
So I don't recommend this as a general purpose solution. Only if you know (=unit tested) that your values are in a set where no combination never results to a false positive (e.g. {"dog", "cat", "horse"}) you might consider this solution. I gave it a second thought and must say don't use that at all. Imagine how your colleagues will love you for searching a bug introduced by that method.
In your case you can do:
if (count(array_unique($tstat, $l1stat, $l2stat, $l3stat)) == 1 //Check if all share the same value (i.e., number of unique values is 1
&& $tstat == 'no_prices')) //If everything is the same and $stat == 'no_prices', then everything is 'no_prices'
{
}
<?php
$tstat = $l1stat = $l2stat = $l3stat = 'no_prices';
$testVars = array($tstat,$l1stat,$l2stat,$l3stat);
if(count(array_filter($testVars, function($x) { return $x === 'no_prices'; })) == count($testVars))
{
print("Correct");
}
Use array_filter with a anonymous callback, and check if its length is greater is equal to original array i.e. all conditions passed,
or if length is greater than zero i.e. any one condition passed
No, this code won't work:
if (($tstat&&$l1stat&&$l2stat&&$l3stat)=='no_prices')
{
//do something
}
Why? Because condition in parentheses, will check result itself - You are comparing boolean to string. So in pseudo-code, thats what your code looks like:
if ( ($tstat is true, $l1stat is true, $l2stat is true, $l3stat is true) == 'no_prices' )
^ whole thing returns true ^ ^ true ^
If you wan't to achieve this, you can use count() and array_unique():
if ($tstat == 'no_prices' && count(array_unique(array($tstat, $l1stat, $l2stat, $l3stat))) == 1)
try this:
$arr = array($tstat,$l1stat,...); //make an array
$arr =array_unique($arr);//unique this array
if(count($arr) == 1 && $arr[0] = 'no_prices'){ // check if only one array element have with same value
echo "got it";
}
demo example
The answer is "no". There's no shorthand to the given condition that will make your code more readable, which should be your top priority. You can improve it though:
define('MYAPP_NO_PRICES', 'no_prices');
if ($tstat === MYAPP_NO_PRICES
&& $l1stat === MYAPP_NO_PRICES
&& $l2stat === MYAPP_NO_PRICES
&& $l3stat === MYAPP_NO_PRICES) {
// do something
}
Having all these vars to check individually is a code smell; you might want to rethink this design so you never have to do this.

Why does (0 == 'Hello') return true in PHP?

Hey, if you have got the following code and want to check if $key matches Hello I've found out, that the comparison always returns true if the variable is 0. I've came across this when an array for a special key and wondered why it's wasn't working as expected.
See this code for an example.
$key = 1;
if ($key != 'Hello') echo 'Hello'; //echoes hello
$key = 2;
if ($key != 'Hello') echo 'Hello'; //echoes hello
$key = 0;
if ($key != 'Hello') echo '0Hello'; //doesnt echo hello. why?
if ($key !== 'Hello') echo 'Hello'; //echoes hello
Can anyone explain this?
The operators == and != do not compare the type. Therefore PHP automatically converts 'Hello' to an integer which is 0 (intval('Hello')). When not sure about the type, use the type-comparing operators === and !==. Or better be sure which type you handle at any point in your program.
Others have already answered the question well. I only want to give some other examples, you should be aware of, all are caused by PHP's type juggling. All the following comparisons will return true:
'abc' == 0
0 == null
'' == null
1 == '1y?z'
Because i found this behaviour dangerous, i wrote my own equal method and use it in my projects:
/**
* Checks if two values are equal. In contrast to the == operator,
* the values are considered different, if:
* - one value is null and the other not, or
* - one value is an empty string and the other not
* This helps avoid strange behavier with PHP's type juggling,
* all these expressions would return true:
* 'abc' == 0; 0 == null; '' == null; 1 == '1y?z';
* #param mixed $value1
* #param mixed $value2
* #return boolean True if values are equal, otherwise false.
*/
function sto_equals($value1, $value2)
{
// identical in value and type
if ($value1 === $value2)
$result = true;
// one is null, the other not
else if (is_null($value1) || is_null($value2))
$result = false;
// one is an empty string, the other not
else if (($value1 === '') || ($value2 === ''))
$result = false;
// identical in value and different in type
else
{
$result = ($value1 == $value2);
// test for wrong implicit string conversion, when comparing a
// string with a numeric type. only accept valid numeric strings.
if ($result)
{
$isNumericType1 = is_int($value1) || is_float($value1);
$isNumericType2 = is_int($value2) || is_float($value2);
$isStringType1 = is_string($value1);
$isStringType2 = is_string($value2);
if ($isNumericType1 && $isStringType2)
$result = is_numeric($value2);
else if ($isNumericType2 && $isStringType1)
$result = is_numeric($value1);
}
}
return $result;
}
Hope this helps somebody making his application more solid, the original article can be found here:
Equal or not equal
pretty much any non-zero value gets converted to true in php behind the scenes.
so 1, 2,3,4, 'Hello', 'world', etc would all be equal to true, whereas 0 is equal to false
the only reason !== works is cause it is comparing data types are the same too
Because PHP does an automatic cast to compare values of different types. You can see a table of type-conversion criteria in PHP documentation.
In your case, the string "Hello" is automatically converted to a number, which is 0 according to PHP. Hence the true value.
If you want to compare values of different types you should use the type-safe operators:
$value1 === $value2;
or
$value1 !== $value2;
In general, PHP evaluates to zero every string that cannot be recognized as a number.
In php, the string "0" is converted to the boolean FALSE http://php.net/manual/en/language.types.boolean.php

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;
}
}
}
}
}

Categories