error in array_filter - php

I have an issue here with filter_array.
below is my code:
$array = array("0","0","1");
function returnzero($d){
if($d=='0'){
return $d;
}
}
$all_zeros = array_filter($array, "returnzero");
echo count($all_zeros);
I would like to filter out all values that none other than zero.
Above is my code. However, the count result returned is always 0.
may I know what is my mistake?
Thanks.

See the documentation on array_filter
You need to be returning true or false, not the number... So your function becomes:
function returnzero($d) { return $d == 0; }

You need to check $d != 0 and it will return all the non-zero values. Trying to return 0 is the same as returning false, so it fails.

Function must returns TRUE.
$array = array(0, 0, 1);
function returnzero($d){
if($d=='0'){
return true;
}
}
$all_zeros = array_filter($array, "returnzero");
echo count ($all_zeros);

Modify the return value to reflect the purpose:
function iszero($d) { return $d == '0'; }
$all_zeros = array_filter($array, 'iszero');
Regards
rbo

The function you pass into array_filter() must return TRUE or FALSE to tell PHP whether the current value being checked matches what you're filtering for. You're returning the number that was passed in. Since you're checking for zeroes, you're returning zero, which PHP interprets as FALSE. You could rewrite the function as follows:
if ($d == 0) {
return TRUE;
} else {
return FALSE;
}
or more concisely
return ($d == 0);

Related

Finding max value in array using recursion in PHP

I know how to use loop to do this simple problem, but I want to play more with recursion. I trying to find max value in array using recursion with PHP. My basic idea is compare the first value of the array with the maximum value of the new array (made by remove the first value of the given array):
function find_max($arr)
{
if ($arr = [])
{
return 0; // base case
} else
{
if ($arr[0] > find_max(rest_of($arr)))
{
return $arr[0];
} else
{
return find_max(rest_of($arr));
}
}
}
function rest_of($arr)
{
unset($arr[0]); // remove the first value of the array
$arr = array_values($arr); // re-index the array
return $arr;
}
But when I run, it seems that it has infinite loop. "Undefined offset: 0"
Can anyone help me?
The problem is because of your base condition here,
if($arr = []){ ...
= is an assignment operator, not comparison operator. What you need here is a comparison operator ==. So it should be,
if($arr == []){
Furthermore, you can change your base condition like this way,
if(count($arr) == 1){
return $arr[0]; // base case
}
So your find_max() function should be like this:
function find_max($arr){
if(count($arr) == 1){
return $arr[0]; // base case
}
if ($arr[0] > find_max(rest_of($arr))){
return $arr[0];
} else{
return find_max(rest_of($arr));
}
}

Group the same array element in PHP

I have this function to check for word sequences:
function sequence($arr_scheme = [], $arr_input = [])
{
$sequence_need = array_values(array_intersect($arr_scheme, $arr_input));
if(!empty($arr_input) && ($sequence_need == $arr_input)):
return true;
else:
return false;
endif;
}
There were my sample and scheme variables:
$sample = "branch of science";
$scheme = "The branch of science concerned of nature and property of matter and energy";
I have converted to array:
$arr_sample = explode(" ",trim(rtrim(rtrim($sample,".")," ")));
echo 'Sample:';
var_dump($arr_sample);
$arr_scheme = explode(" ",trim(rtrim(rtrim($scheme,".")," ")));
echo '<br/>Scheme:';
var_dump($arr_scheme);
Now, I check the sequences:
$result = sequence($arr_scheme, $arr_sample);
The result:
echo '<br/>Result:';
var_dump($result);
When I set the variable $sample to
"branch science" the result will return true. This was fine.
However when I set the variable sample to
"branch of science" the result will return false .
Reason - the word of was more than 1, how I can solve this problem?
Find first input word in the scheme (can be multiple).
Then run recursive for rests of arrays.
function sequence($arr_scheme = [], $arr_input = [])
{
if (!$arr_input) return true;
$first = array_shift($arr_input);
$occurences = array_keys($arr_scheme, $first);
if (!$occurences) return false;
foreach ($occurences as $o) { // loop first word occurences
$found = sequence(array_slice($arr_scheme, $o), $arr_input);
if ($found) return true;
}
return false;
}
First word later occurences should not matter anything for match.
So, this tail-recursion function will work even better:
function sequence($arr_scheme = [], $arr_input = [])
{
if (!$arr_input) return true;
$first = array_shift($arr_input);
$index = array_search($arr_scheme, $first);
if ($index === false) return false; // not found
return sequence(array_slice($arr_scheme, $index), $arr_input);
}
You can research more at here. Note: "Returns an array containing all of the values in array1 whose values exist in all of the parameters.". Then, look at in your result, when you call var_dump($arr_scheme);, you see "of" appears 3 times. and size of array result after compare is 5. however, size of array $sample is 3. So, you can understand why it returns false.
Solution for this case. why dont you try to use regular expression? or strpos function?
$sequence_need = array_unique($sequence_need);
array_unique removes any duplicate values in your array.. the duplicate 'of' will be removes.. Hope it helps..
I think you should go with array_diff(). It computes the difference of arrays and returns the values in $arr_sample that are not present in $arr_scheme.
So,
array_diff($arr_sample, $arr_scheme)
will return an empty array if all the values in $arr_sample are present in $arr_scheme
The next step would be to count the length of the array returned by array_diff(). If it equals 0, then we should return true
return count(array_diff($arr_sample, $arr_scheme)) === 0;
The above return statement could be presented as:
$diff = array_diff($arr_sample, $arr_scheme);
if (count($diff) === 0) {
return true;
} else {
return false;
}
From your comments it became clear that your function should return true
if all the elements of $arr_input are present in $arr_scheme in the same order
that they appear in $arr_scheme. Othewise it should return false
So,
sequence(['branch', 'of', 'science', 'and', 'energy'], ['branch', 'of', 'energy'])
should return true
and
sequence(['branch', 'of', 'science', 'and', 'energy'], ['science', 'of', 'branch'])
should return false
In this case the function sequence() could be defined as follows:
function sequence($arr_scheme = [], $arr_input = [])
{
//test if all elements of $arr_input are present in $arr_scheme
$diff = array_diff($arr_input, $arr_scheme);
if ($diff) {
return false;
}
foreach ($arr_input as $value) {
$pos = array_search($value, $arr_scheme);
if (false !== $pos ) {
$arr_scheme = array_slice($arr_scheme, $pos + 1);
continue;
}
return false;
}
return true;
}

in_array() does not seem to check after key 2

I have a simple function that should just give me TRUE or FALSE if a value is find in an array.
function bypass($user, $bypassUsers){
$users = explode(",", $bypassUsers);
// trim($users);
if(in_array($user,$users)){
return true;
} else {
return false;
}
}
While to me everything looks of when I have more than 2 values in the array, the function returns FALSE as if in_array() does not see from key [2].
Any idea?
If you want to apply trim to all elements, instead of:
$users = explode(",", $bypassUsers);
trim($users);
You should do this instead:
$users = array_map('trim', explode(',', $bypassUsers));
It applies trim() to the result of explode(). Afterwards, you can return the result in one statement:
return in_array($user, $users, true);
// third argument determines whether to use == or === for comparison
function bypass($user, $bypassUsers){
$users = explode(",", $bypassUsers);
foreach($users as $key=>$usr){
$users[$key] = trim($usr);
}
if(in_array(trim($user),$users)){
return true;
} else {
return false;
}
}
Trim is the problem because it works with string not with an array

PHP is there a true() function?

I'm writing a function named all to check all elements inside an array $arr, returning a single boolean value (based of $f return value). This is working fine passing custom functions (see the code with $gte0 been passed to all).
However sometimes one want just check that an array contains all true values: all(true, $arr) will not work becase true is passed as boolean (and true is not a function name). Does PHP have a native true() like function?
function all($f, array $arr)
{
return empty($arr) ? false : array_reduce($arr, function($v1, $v2) use ($f) {
return $f($v1) && $f($v2);
}, true);
}
$test = array(1, 6, 2);
$gte0 = function($v) { return $v >= 0; }
var_dump(all($gte0, $test)); // True
$test = array(true, true, false);
$id = function($v) { return $v; } // <-- this is what i would avoid
var_dump(all($id, $test)); // False
all(true, $test); // NOT WORKING because true is passed as boolean
all('true', $test); // NOT WORKING because true is not a function
EDIT: another way could be checking $f in all function:
$f = is_bool($f) ? ($f ? function($v) { return $v; }
: function($v) { return !$v; } ): $f;
After adding this, calling all with true is perfectly fine.
intval might do what you're looking for (especially as the array only contains integers in your example):
var_dump(all('intval', $test)); // False
However, many types to integer conversions are undefined in PHP and with float this will round towards zero, so this might not be what you want.
The more correct "function" would be the opposite of boolean true: empty, but it's not a function, so you can't use it (and invert the return value):
var_dump(!all('empty', $test)); // Does not work!
And there is no function called boolval or similar in PHP, so write it yourself if you need it ;)
Additionally your all function could be optimized. While iterating, if the current result is already FALSE, the end result will always be FALSE. And no need to call $f() n * 2 times anyway:
function all($f, array $arr)
{
$result = (bool) $arr;
foreach($arr as $v) if (!$f($v)) return FALSE;
return $result;
}
Edit: knittl is right pointing to array_filter, it converts to boolean with no function given which seems cool as there is no "boolval" function:
function all($f, array $arr)
{
return ($c = count($arr))
&& ($f ? $arr = array_map($f, $arr) : 1)
&& $c === count(array_filter($arr));
}
var_dump(all(0, $test)); // False
Making the first function parameter optional will do you a proper bool cast on each array element thanks to array_filter.
Better to pass in a function to map the values to booleans that you can then reduce to a final value.
function all($map, $data) {
if (empty($data)) { return false; }
$reduce = function($f, $n) {
return $f && $n;
};
return array_reduce(array_map($map, $data), $reduce, true);
}
$gte0 = function($v) { return $v >= 0; };
$gte2 = function($v) { return $v >= 2; };
$data = array(1, 2, 3, 4, 5);
var_dump(all($gte0, $data));
var_dump(all($gte2, $data));
Then the result of the function remains expectant but the test can be slotted in as needed. You can go a step further and allow both the map and reduce function to be passed in.
function mr($map, $reduce, $data) {
return array_reduce(array_map($map, $data), $reduce, true);
}
You could use PHP's array_filter function, it will remove all 'falsy' values from an array if no callback is specified:
$a = array ( true, true, false );
var_dump($a == array_filter($a));
There isn't any true() function in PHP, you should compare the value to true.
try
return ($f === $v1) && ($f === $v2);
instead of
return $f($v1) && $f($v2);
I think this should work:
function all($f, array $arr)
{
return empty($arr) ? false : array_reduce($arr, function($v1, $v2) use ($f) {
return $f($v1) && $f($v2);
}, true);
}
function isTrue($a)
{
return true === $a;
}
all("isTrue", $test);

Is there a method to check if all array items are '0'?

I have an array
$data = array( 'a'=>'0', 'b'=>'0', 'c'=>'0', 'd'=>'0' );
I want to check if all array values are zero.
if( all array values are '0' ) {
echo "Got it";
} else {
echo "No";
}
Thanks
I suppose you could use array_filter() to get an array of all items that are non-zero ; and use empty() on that resulting array, to determine if it's empty or not.
For example, with your example array :
$data = array(
'a'=>'0',
'b'=>'0',
'c'=>'0',
'd'=>'0' );
Using the following portion of code :
$tmp = array_filter($data);
var_dump($tmp);
Would show you an empty array, containing no non-zero element :
array(0) {
}
And using something like this :
if (empty($tmp)) {
echo "All zeros!";
}
Would get you the following output :
All zeros!
On the other hand, with the following array :
$data = array(
'a'=>'0',
'b'=>'1',
'c'=>'0',
'd'=>'0' );
The $tmp array would contain :
array(1) {
["b"]=>
string(1) "1"
}
And, as such, would not be empty.
Note that not passing a callback as second parameter to array_filter() will work because (quoting) :
If no callback is supplied, all entries of input equal to FALSE (see
converting to boolean) will be removed.
How about:
// ditch the last argument to array_keys if you don't need strict equality
$allZeroes = count( $data ) == count( array_keys( $data, '0', true ) );
Use this:
$all_zero = true;
foreach($data as $value)
if($value != '0')
{
$all_zero = false;
break;
}
if($all_zero)
echo "Got it";
else
echo "No";
This is much faster (run time) than using array_filter as suggested in other answer.
you can loop the array and exit on the first non-zero value (loops until non-zero, so pretty fast, when a non-zero value is at the beginning of the array):
function allZeroes($arr) {
foreach($arr as $v) { if($v != 0) return false; }
return true;
}
or, use array_sum (loops complete array once):
function allZeroes($arr) {
return array_sum($arr) == 0;
}
#fireeyedboy had a very good point about summing: if negative values are involved, the result may very well be zero, even though the array consists of non-zero values
Another way:
if(array_fill(0,count($data),'0') === array_values($data)){
echo "All zeros";
}
Another quick solution might be:
if (intval(emplode('',$array))) {
// at least one non zero array item found
} else {
// all zeros
}
if (!array_filter($data)) {
// empty (all values are 0, NULL or FALSE)
}
else {
// not empty
}
I'm a bit late to the party, but how about this:
$testdata = array_flip($data);
if(count($testdata) == 1 and !empty($testdata[0])){
// must be all zeros
}
A similar trick uses array_unique().
You can use this function
function all_zeros($array){//true if all elements are zeros
$flag = true;
foreach($array as $a){
if($a != 0)
$flag = false;
}
return $flag;
}
You can use this one-liner: (Demo)
var_export(!(int)implode($array));
$array = [0, 0, 0, 0]; returns true
$array = [0, 0, 1, 0]; returns false
This is likely to perform very well because there is only one function call.
My solution uses no glue when imploding, then explicitly casts the generated string as an integer, then uses negation to evaluate 0 as true and non-zero as false. (Ordinarily, 0 evaluates as false and all other values evaluate to true.)
...but if I was doing this for work, I'd probably just use !array_filter($array)

Categories