Perform logic operations on boolean array values - php

I have an array with boolean values, e.g.
$myarray = array(true, false, false, true, false);
Now I want to perform some logic operations on my array values, so I get the output:
FALSE
from my array.

You're trying to treat booleans as strings, which is fundamentally wrong. What you want is, for example, an array reduction:
$res = array_reduce($myarray, function ($a, $b) { return $a && $b; }, true);
// default value ^^^^
Or a more efficient short-circuiting all function:
function all(array $values) {
foreach ($values as $value) {
if (!$value) {
return false;
}
}
return true;
}
if (all($myarray)) ...

You could just search your array for false, and if it's present, return false, and if not return true:
$result = (array_search(false, $myarray, true) === false);
Since you edited your question, if you want it to return 0 or 1 just do:
$result = (array_search(false, $myarray, true) === false) ? 1 : 0;

You could try this:
$res = true;
foreach ($myarray as $item) $res &= $item;
echo var_dump($res);
A bit less elegant, but it should work. You'll have an integer in the end because we're using bit logic here, could be improved.
For a OR case you could do almost the same thing:
$res = true;
foreach ($myarray as $item) $res |= $item;
echo var_dump($res);

Related

Check if all string values of one array are either similar or sub-string of another array values

Ok posting this query after going through many similar issues but they took into consideration only numeric values. So my issue is:
I have 2 arrays -
$a = ["XYZ1250H100",
"XYZ1280H130",
"XYZ1250H150",
"XYZ3300H200",
"XYZ3350H200",
"XYZ33350H280Ada08",
"XYZ33450H300Ada08",
"XYZ33508H406Ada08"];
and
$b = ["XYZ0L200H150A4c00",
"350L610H457Ada08",
"XYZ33762H610Ada08",
"350L914H610Ada08",
"3700L250H200A410b",
"XYZ33457H305Ada08",
"XYZ4550H100MMQOJ",
"XYZ4580H130Ada08",
"XYZ4550H150A69b5",
"3101L280H356A8b83",
"XYZ4550H1501FC5Z",
"3116L150H15074QFR",
"XYZ1250H200A21ac",
"3101L750H500A8b83",
"350L356H279Ada08",
"XYZ1250H200A3f1c",
"3700L153H102A8d96",
"XYZ4550H150Ada08",
"XYZ4580H130A69b5",
"350L1830H610Ada08",
"3700L153H102A4c00",
"XYZ4550H150STD9J",
"3800L200H1505CZJI",
"XYZ4550H100A69b5",
"XYZ331370H450Ada08"
];
I need to see if values of array $a are there in array $b, I tried to use array_diff() and array_intersect() but that didn't solve the purpose. What I want is if the 2 arrays are matched then it should return either true or false. So for example if we consider value in $a -> "XYZ1280H130" and value in $b -> "XYZ1280H130A69b5" then it should be considered as a matched value (coz former is a sub-string of latter value) and true should be return and same for all similar values.
I tried something like this but it gives back all values of array $b everytime:
$result = array_filter($a, function($item) use($b) {
foreach($b as $substring)
if(strpos($item, $substring) !== FALSE) return TRUE;
return FALSE;
});
Please let me know if I missed something. Thanks in advance.
Use regex:
foreach($b as $search){
foreach($a as $sub){
if(preg_match("/$sub/",$search)){ echo "found ".$sub." in ".$search;}
}
}
You could use array_map.
But this should give you the result you want as well :
function test($a, $b) {
foreach($a as $first) {
foreach($b as $second) {
if(strpos($b, $a) !== false) return true;
}
}
}
Modified one of the answers above by #clearshot66 to get the desired result:
function match_them($a, $b){
foreach($b as $search){
foreach($a as $key => $val){
if(preg_match("/$val/",$search)){unset($a[$key]);}
}
}
return count($a);
}
var_dump(match_them($a, $b));

Search for part of string in multidimentional array returned by Drupal

I'm trying to find a part of a string in a multidimentional array.
foreach ($invitees as $invitee) {
if (in_array($invitee, $result)){
echo 'YES';
} else {
echo 'NO';
}
}
the $invitees array has 2 elements:
and $result is what I get from my Drupal database using db_select()
What I'm trying to do is, if the first part from one of the emails in $invitees is in $result it should echo "YES". (the part before the "#" charather)
For example:
"test.email" is in $result, so => YES
"user.one" is not in $result, so => NO
How do i do this? How can I search for a part of a string in a multidimentional array?
Sidenote: I noticed that the array I get from Drupal ($result) has 2 "Objects" which contain a "String", and not arrays like I would expect.
For example:
$test = array('red', 'green', array('apple', 'banana'));
Difference between $result and $test:
Does this have any effect on how I should search for my string?
Because $result is an array of objects, you'll need to use a method to access the value and compare it. So, for instance you could do:
//1: create new array $results from array of objects in $result
foreach ($result as $r) {
$results[] = get_object_vars($r);
}
//2: expanded, recursive in_array function for use with multidimensional arrays
function in_array_r($needle, $haystack, $strict = false) {
foreach ($haystack as $item) {
if (($strict ? $item === $needle : $item == $needle) || (is_array($item) && in_array_r($needle, $item, $strict))) {
return true;
}
}
return false;
}
//3: check each element of the $invitees array
foreach ($invitees as $invitee) {
echo in_array_r($invitee, $results) ? "Yes" : "No";
}
Also, for some illumination, check out this answer.
You can search through the array using preg_grep, and use a wildcard for anything before and after it. If it returns a value (or values), use key to get the index of the first one. Then do a check if its greater than or equal to 0, which means it found a match :)
<?php
$array = array('test1#gdfgfdg.com', 'test2#dgdgfdg.com', 'test3#dfgfdgdfg');
$invitee = 'test2';
$result = key(preg_grep('/^.*'.$invitee.'.*/', $array));
if ($result >= 0) {
echo 'YES';
} else {
echo 'NO';
}
?>
Accepted larsAnders's answer since he pointed me in to direction of recursive functions.
This is what I ended up using (bases on his answer):
function Array_search($array, $string) {
foreach ($array as $key => $value) {
if (is_array($value)) {
Array_search($array[$key], $string);
} else {
if ($value->data == $string) {
return TRUE;
}
}
}
return FALSE;
}

check if association keys exists in a particular array

I'm trying to build a function that checks if there's a value at a particular location in an array:
function ($array, $key) {
if (isset($array[$key]) {
return true;
}
return false;
}
but how can I accomplish this in a multi array? say I want to check if a value is set on $array[test1][test2]
Pass an array of keys, and recurse into the objects you find along the way:
function inThere($array, $keys)
{
$key = $keys; // if a single key was passed, use that
$rest = array();
// else grab the first key in the list
if (is_array($keys))
{
$key = $keys[0];
$rest = array_slice($keys, 1);
}
if (isset($array[$key]))
{
if (count($rest) > 0)
return inThere($array[$key], $rest);
else
return true;
}
return false;
}
So, for:
$foo = array(
'bar' => array( 'baz' => 1 )
);
inThere($foo, 'bar'); // == true
inThere($foo, array('bar')); // == true
inThere($foo, array('bar', 'baz')); // == true
inThere($foo, array('bar', 'bazX')); // == false
inThere($foo, array('barX')); // == false
Here is a non-recursive way to check for if a multi-level hashtable is set.
// $array it the container you are testing.
// $keys is an array of keys that you want to check. [key1,key2...keyn]
function ($array, $keys) {
// Is the first key set?
if (isset($array[$key]) {
// Set the test to the value of the first key.
$test = $array[$key];
for($i = 1; $i< count($keys); $i++){
if (!isset($test[$keys[$i]]) {
// The test doesn't have a matching key, return false
return false;
}
// Set the test to the value of the current key.
$test = $test[$keys[$i]];
}
// All keys are set, return true.
return true;
} else {
// The first key doesn't exist, so exit.
return false;
}
}
While I probably wouldn't build a function for this, perhaps you can put better use to it:
<?php
function mda_isset( $array )
{
$args = func_get_args();
unset( $args[0] );
if( count( $args ) > 0 )
{
foreach( $args as $x )
{
if( array_key_exists( $x, $array ) )
{
$array = $array[$x];
}
else
{
return false;
}
}
if( isset( $array ) )
{
return true;
}
}
return false;
}
?>
You can add as many arguments as required:
// Will Test $array['Test1']['Test2']['Test3']
$bool = mda_isset( $array, 'Test1', 'Test2', 'Test3' );
It will first check to make sure the array key exists, set the array to that key, and check the next key. If the key is not found, then you know it doesn't exist. If the keys are all found, then the value is checked if it is set.
I'm headed out, but maybe this. $keys should be an array even if one, but you can alter the code to check for an array of keys or just one:
function array_key_isset($array, $keys) {
foreach($keys as $key) {
if(!isset($array[$key])) return false;
$array = $array[$key];
}
return true;
}
array_key_isset($array, array('test1','test2'));
There's more universal method but it might look odd at first:
Here we're utilizing array_walk_recursive and a closure function:
$array = array('a', 'b', array('x', 456 => 'y', 'z'));
$search = 456; // search for 456
$found = false;
array_walk_recursive($array, function ($value, $key) use ($search, &$found)
{
if ($key == $search)
$found = true;
});
if ($found == true)
echo 'got it';
The only drawback is that it will iterate over all values, even if it's already found the key. This is good for small array though

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

Array AND() ? Logical ANDing of all elements

I have an array and I want to find out if there is at least one false value in it. I was thinking of creating an array_and() function, that just performs a logical AND on all the elements. It would return true if all values are true, otherwise false. Am I over-engineering?
Why dont you just use
in_array — Checks if a value exists in an array
Example:
// creates an array with 10 booleans having the value true.
$array = array_fill(0, 10, TRUE);
// checking if it contains a boolean false
var_dump(in_array(FALSE, $array, TRUE)); // FALSE
// adding a boolean with the value false to the array
$array[] = FALSE;
// checking if it contains a boolean false now
var_dump(in_array(FALSE, $array, TRUE)); // TRUE
It would return true if all values are true, otherwise false.
Returns true if array is non empty and contains no false elements:
function array_and(arary $arr)
{
return $arr && array_reduce($arr, function($a, $b) { return $a && $b; }, true));
}
(Note that you would need strict comparison if you wanted to test against the false type.)
Am I over-engineering?
Yes, because you could use:
in_array(false, $arr, true);
There's nothing wrong with this in principle, as long as you don't AND all of the values indiscriminately; that is, you should terminate as soon as the first false is found:
function array_and(array $array)
{
foreach ($array as $value)
{
if (!$value)
{
return false;
}
}
return true;
}
you should be able to implement a small function that takes an array and iterates over it checking each member to see if it is false. Return a bool from the function based on the outcome of your checking....
Easy but ugly => O(N)
$a = array(1, 2, false, 5, 6, 'a');
$_there_is_a_false = false
foreach ($a as $b) {
$_there_is_a_false = !$b ? true : $_there_is_a_false;
}
another option: array-filter
Why not just use array_product()
$set = array(1,1,1,1,0,0);
$result = array_product($set);
Output: 0
AND Logical is essentially a multiplier.
1 * 1 = 1
1 * 0 = 0
0 * 1 = 0
0 * 0 = 0

Categories