Checking value against an array issue - php

This is killing me. It seems so simple, but for some reason I cannot get it to work.
Basically what I have is a function that accepts a single string $name as a variable, then it goes through and checks that variable against values in an array. If the variable is found in the array is returns TRUE. This function is called from within a foreach loop in another function (which submits a new $name variable each time.)
I have tried 3 different ways to check the variable against the array but it never works properly.
1.) using another foreach() loop
function check($name) {
$commaSeparatedString = 'First Name, Second Name, Third Name';
$array = explode(",", $commaSeparatedString);
foreach($array as $arrayValue) {
if($arrayValue == $name) {
return TRUE;
}
else {
return FALSE;
}
}
}
2.) using in_array()
function check($name) {
$commaSeparatedString = 'First Name, Second Name, Third Name';
$array = explode(",", $commaSeparatedString);
if(in_array($name, $array, TRUE)) {
return TRUE;
}
else {
return FALSE;
}
}
3.) looping through each value in the array manually and checking for a match
function check($name) {
$commaSeparatedString = 'First Name, Second Name, Third Name';
$array = explode(",", $commaSeparatedString);
$count = count($array);
$i = 0;
while($i<=$count) {
if(isset($array[$i]) && $array[$i] == $name) {
$i++;
echo $i;
return TRUE;
break;
}
else {
$i++;
echo $i;
return FALSE; }
}
}
Here a simplified part of the function where check() is run:
function loopCheck() {
$group = array($obj1, $obj2, $obj3, $obj4, $obj5);
foreach($group as $groupValue) {
$name = $groupValue->name;
$ignore = $this->check($name);
if($ignore == TRUE) { }
else { echo $name; }
}
}
The result for all three variations of check() is the same. It returns TRUE for every $groupValue except the first value of $array. So if the $name of $obj2 was 'First Name' it would return TRUE, but if the $name of $obj3 was 'Second Name' is still returns FALSE. I echoed $i for the third variation at one point and the value consistently stayed at 1, so I know there is some error with that method, but I don't know why the result would be the same using the other 2 methods.

There are several issues with your code. The one that causes the failure of all code, is that you explode by ',', thus leaving a whitespace in your strings. You should explode on ', '.
But the first code is erroneous still: The foreach will return on the first iteration, always, thus checking only the first element. The loop should be:
foreach ($array as $arrayValue) {
if ($arrayValue == $name) {
return true;
}
}
return false;
Same applies to your last code.
The best variant is probably the second, here is a slightly shorter, adjusted variant:
function check($name) {
$commaSeparatedString = 'First Name, Second Name, Third Name';
return in_array($name, explode(', ', $commaSeparatedString), true));
}

You should not put
Return false;
On your else, you should put it after the whole loop.
Also keep in mind that if you wanna explode a, b, c to be [a,b,c] you have to use
explode(", ",$str); //note the space

The problem is that when you make the explode in the check function, some pieces have spaces because there is a space after the comma.

Did you trim() your strings?
It would work on the first string as it starts with "First String" but the second explode()ed string would be "spaceSecond String".

I think any of those techniques will work, but you just have small errors.
I've fixed the first one below. You don't want to return false in an else clause. you want it AFTER the foreach loop, only if it fails to match EVERY time.
function check($name) {
$commaSeparatedString = 'First Name, Second Name, Third Name';
$array = explode(",", $commaSeparatedString);
foreach($array as $arrayValue) {
if($arrayValue == $name) {
return TRUE;
}
}
return false;
}
The in_array version is potentially simpler. Notice that there is no reason for if ($val) {return true;} else {return false;}, just do return $val
function check($name)
{
$csvs = 'First Name, Second Name, Third Name';
return in_array($name, explode(', ', $csv));
//return in_array(trim(strtoupper($name)), array_map('trim', explode(', ', strtoupper($csv))));
//try this second way is kind of over-kill thorough, but try it if you still get false where true is expected
}
You also have to either trim the strings of the array you make or explode(', ' $csv) with a space. Otherwise the elements of array will have a leading space.

Related

in_array() keeps appending values if looping through db rows

I need to identify every instance where a value in one array (needle) occurs in another array (haystack). in_array() seems to be my best option, and the code below works perfectly until I need to use it on rows fetched from a db - it keeps appending values instead of setting them each time it's called.
While I can't actually use unset() in this situation, I was surprised to discover that even that didn't seem to resolve the problem.
UPDATE - Example of what's being returned
I temporarily changed the db values so that $needles has only value per row (in order to make it possible to sort through the values filling up my screen ;-))
False;
False; False; True;
False; False; True; False; True;
False; False; True; False; True; False; True;
False; False; True; False; True; False; True; False;
This works correctly
(I've posted a functional example here)
$needles = array('John', 'Alex');
$haystack = array('John','Alexander','Kim', 'Michael');
foreach ($needles as $needle) {
if (in_array($needle, $haystack) ) {
$Match = 'True';
}
else {
$Match = 'False';
}
}
This keeps appending values - Edited to reflect the code I'm using
$Customer_Categories_Arr = array('Casual','Trendy');
if ($stmt->columnCount()) {
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$Product_Categories_Arr[]=$row["Taste_Category"];
// Use when column contains CSV
// $Product_Categories_Arrx = explode(',', trim($Product_Categories_Arr[0]));
foreach ($Product_Categories_Arr as $Product_Category_Arr) {
if (in_array($Product_Category_Arr, $Customer_Categories_Arr)){
$Matches_Product_Category = "True";
} else {
$Matches_Product_Category = "False";
}
echo $Product_Category_Arr, ', ', $Matches_Product_Category, '; ';
}
}
}
It is not really clear what you are trying to do. But maybe this would help:
$customerCategories = array('Casual', 'Trendy');
if( $stmt->columnCount() ){
while( $row = $stmt->fetch( PDO::FETCH_ASSOC )){
$productCategoryRow = $row[ 'Taste_Category' ];
// If it is not working, try uncommenting the next line
// $productCategories = [];
$productCategories = explode( ',', trim( $productCategoryRow ));
$match = "False";
foreach( $productCategories as $productCategory ){
if( in_array( $productCategory, $customerCategories )){
$match = "True";
}
echo $match . ";";
}
}
}
This prints your result on the screen every time a loop is done. Is this what you mean?
If you want the second block of code to do what the first block of code (which works correctly) does, then the second block should look like this -
if ($stmt->columnCount()) {
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$needle =$row["product_var"];
$Match = "False";
if (in_array($needle, $haystack)){
$Match = "True";
}
}
}
You don't need do use the foreach because that is replaced by the while loop in the second block.
I am going to try an solve this. I think the problem is with:
$needles[]=$row["product_var"];
I think this should be:
$needles=$row["product_var"];
The column "product_var" contains an CSV (as you mentioned), so I can make an example like this:
$csv = "jake;john;alex;kim";
An example with brackets ($needles[]):
for($i=0; $i<5; $i++) {
$needles[] = explode(";", $csv);
echo(count($needles).", ");
}
returns:
1, 2, 3, 4, 5,
edit (for more explaining):
if I use print_r I see the array expanding, exactly how it happens in your example:
step 1: it adds an array to $needles with values ('jake','john','alex','kim')
step 2: it adds an array to $needles, so it contains 2x the values ('jake','john','alex','kim')
step 3: it adds an array to $needles, so it contains 3x the values ('jake','john','alex','kim')
etc.
Now without the brackets ($needles):
for($i=0; $i<5; $i++) {
$needles = explode(";", $csv);
echo(count($needles).", ");
}
This returns:
4, 4, 4, 4, 4,
And every time the array simply contains the values ('jake','john','alex','kim') -which is what you want.
Could this explain the "expanding values"? (or am I just doing something really stupid which has nothing to do with your problem??)
edit:
If this is what is going wrong, then you are adding to an array, instead of only using the new array from $row["product_var"] (hope this makes any sense; it seems I am pretty bad at explaining what's happening).

PHP Function that can return value from an array key a dynamic number of levels deep

Using PHP, I would like to write a function that accomplishes what is shown by this pseudo code:
function return_value($input_string='array:subArray:arrayKey')
{
$segments = explode(':',$input_string);
$array_depth = count(segments) - 1;
//Now the bit I'm not sure about
//I need to dynamically generate X number of square brackets to get the value
//So that I'm left with the below:
return $array[$subArray][$arrayKey];
}
Is the above possible? I'd really appreciate some pointer on how to acheive it.
You can use a recursive function (or its iterative equivalent since it's tail recursion):
function return_value($array, $input_string) {
$segments = explode(':',$input_string);
// Can we go next step?
if (!array_key_exists($segments[0], $array)) {
return false; // cannot exist
}
// Yes, do so.
$nextlevel = $array[$segments[0]];
if (!is_array($nextlevel)) {
if (1 == count($segments)) {
// Found!
return $nextlevel;
}
// We can return $nextlevel, which is an array. Or an error.
return false;
}
array_shift($segments);
$nextsegments = implode(':', $segments);
// We can also use tail recursion here, enclosing the whole kit and kaboodle
// into a loop until $segments is empty.
return return_value($nextlevel, $nextsegments);
}
Passing one object
Let's say we want this to be an API and pass only a single string (please remember that HTTP has some method limitation in this, and you may need to POST the string instead of GET).
The string would need to contain both the array data and the "key" location. It's best if we send first the key and then the array:
function decodeJSONblob($input) {
// Step 1: extract the key address. We do this is a dirty way,
// exploiting the fact that a serialized array starts with
// a:<NUMBEROFITEMS>:{ and there will be no "{" in the key address.
$n = strpos($input, ':{');
$items = explode(':', substr($input, 0, $n));
// The last two items of $items will be "a" and "NUMBEROFITEMS"
$ni = array_pop($items);
if ("a" != ($a = array_pop($items))) {
die("Something strange at offset $n, expecting 'a', found {$a}");
}
$array = unserialize("a:{$ni}:".substr($input, $n+1));
while (!empty($items)) {
$key = array_shift($items);
if (!array_key_exists($key, $array)) {
// there is not this item in the array.
}
if (!is_array($array[$key])) {
// Error.
}
$array = $array[$key];
}
return $array;
}
$arr = array(
0 => array(
'hello' => array(
'joe','jack',
array('jill')
)));
print decodeJSONblob("0:hello:1:" . serialize($arr));
print decodeJSONblob("0:hello:2:0" . serialize($arr));
returns
jack
jill
while asking for 0:hello:2: would get you an array { 0: 'jill' }.
you could use recursion and array_key_exists to walk down to the level of said key.
function get_array_element($key, $array)
{
if(stripos(($key,':') !== FALSE) {
$currentKey = substr($key,0,stripos($key,':'));
$remainingKeys = substr($key,stripos($key,':')+1);
if(array_key_exists($currentKey,$array)) {
return ($remainingKeys,$array[$currentKey]);
}
else {
// handle error
return null;
}
}
elseif(array_key_exists($key,$array)) {
return $array[$key];
}
else {
//handle error
return null;
}
}
Use a recursive function like the following or a loop using references to array keys
<?php
function lookup($array,$lookup){
if(!is_array($lookup)){
$lookup=explode(":",$lookup);
}
$key = array_shift($lookup);
if(!isset($array[$key])){
//throw exception if key is not found so false values can also be looked up
throw new Exception("Key does not exist");
}else{
$val = $array[$key];
if(count($lookup)){
return lookup($val,$lookup);
}
return $val;
}
}
$config = array(
'db'=>array(
'host'=>'localhost',
'user'=>'user',
'pass'=>'pass'
),
'data'=>array(
'test1'=>'test1',
'test2'=>array(
'nested'=>'foo'
)
)
);
echo "Host: ".lookup($config,'db:host')."\n";
echo "User: ".lookup($config,'db:user')."\n";
echo "More levels: ".lookup($config,'data:test2:nested')."\n";
Output:
Host: localhost
User: user
More levels: foo

Which member of array does the string contain in PHP?

How can I check if a string contains a member of an array, and return the index (integer) of the relevant member?
Let's say my string is this :
$string1 = "stackoverflow.com";
$string2 = "superuser.com";
$r = array("queue" , "stack" , "heap");
get_index($string1 , $r); // returns 1
get_index($string2 , $r); // returns -1 since string2 does not contain any element of array
How can I write this function in an elegant (short) and efficient way ?
I found a function (expression ? ) that checks if the string contains a member of an array :
(0 < count(array_intersect(array_map('strtolower', explode(' ', $string)), $array)))
but this is a boolean. does the count() function return what I want in this statement ?
Thanks for any help !
function get_index($str, $arr){
foreach($arr as $key => $val){
if(strpos($str, $val) !== false)
return $key;
}
return -1;
}
Demo: https://eval.in/95398
This will find the number of matching elements in your array, if you want all matching keys, use the commented lines instead:
function findMatchingItems($needle, $haystack){
$foundItems = 0; // start counter
// $foundItems = array(); // start array to save ALL keys
foreach($haystack as $key=>$value){ // start to loop through all items
if( strpos($value, $needle)!==false){
++$foundItems; // if found, increase counter
// $foundItems[] = $key; // Add the key to the array
}
}
return $foundItems; // return found items
}
findMatchingItems($string1 , $r);
findMatchingItems($string2 , $r);
If you want to return all matching keys, just change $foundItems to an array and add the keys in the if-statement (switch to the commented lines).
If you only want to know if something matches or not
function findMatchingItems($needle, $haystack){
if( strpos($value, $needle)!==false){
return true;
break; // <- This is important. This stops the loop, saving time ;)
}
return false;// failsave, if no true is returned, this will return
}
I would do a function like this:
function getIndex($string, $array) {
$index = -1;
$i = 0;
foreach($array as $array_elem) {
if(str_pos($array_elem, $string) !== false) {
$index = $i;
}
$i++;
}
return $index;
}

Difficulty checking if elements in array are type integer PHP

I am trying to detect if one or more variables contain numbers. I have tried a few different methods, but I have not been entirely successful. Here is what I have tried.
<?php
$one = '1';
$two = '2';
$a1 = '3';
$a2 = '4';
$a3 = '5';
$string_detecting_array = array();
array_push($string_detecting_array, $one,$two,$a1,$a2,$a3);
foreach ($string_detecting_array as $key) {
if (is_numeric($key)) {
echo 'Yes all elements in array are type integer.';
}
else {
echo "Not all elements in array were type integer.";
}
}
?>
I haven't been successful using this method. Any ideas? Thankyou in advance!
First off, your loop logic is wrong: you should process all the items in the array before reaching a verdict. The shortest (although not most obvious) way to do this is with
$allNumbers = $array == array_filter($array, 'is_numeric');
This works because array_filter preserves keys and comparing arrays with == checks element counts, keys, and values (and the values here are primitives, so can be trivially compared).
A more mundane solution would be
$allNumbers = true;
foreach ($array as $item) {
if (!is_numeric_($item)) {
$allNumbers = false;
break;
}
}
// now $allNumbers is either true or false
Regarding the filter function: if you only want to allow the characters 0 to 9, you want to use ctype_digit, with the caveat that this will not allow a minus sign in front.
is_numeric will allow signs, but it will also allow floating point numbers and hexadecimals.
gettype will not work in this case because your array contains numeric strings, not numbers.
You can use gettype if you want to explicitly know if the variable is a number. Using is_numeric will not respect types.
If you are intending to use is_numeric but want to know if all elements are, then proceed as follows:
$all_numeric = true;
foreach ($string_detecting_array as $key) {
if (!(is_numeric($key))) {
$all_numeric = false;
break;
}
}
if ($all_numeric) {
echo 'Yes all elements in array are type integer.';
}
else {
echo "Not all elements in array were type integer.";
}
You can chain array_map with array_product to get a one-liner expression:
if (array_product(array_map('is_numeric', $string_detecting_array))) {
echo "all values are numeric\n";
} else {
echo "not all keys are numeric\n";
}
You can use this:
$set = array(1,2,'a','a1','1');
if(in_array(false, array_map(function($v){return is_numeric($v);}, $set)))
{
echo 'Not all elements in array were type integer.';
}
else
{
echo 'Yes all elements in array are type integer.';
}
You can create own batch testing function. It may be static function on your utility class!
/**
* #param array $array
* #return bool
*/
public static function is_all_numeric(array $array){
foreach($array as $item){
if(!is_numeric($item)) return false;
}
return true;
}
Use gettype()
http://php.net/manual/en/function.gettype.php
You have to set a flag and look at all the items.
$isNumeric = true;
foreach ($string_detecting_array as $key) {
if (!is_numeric($key)) {
$isNumeric = false;
}
}
if ($isNumeric) {
echo 'Yes all elements in array are type integer.';
}
else {
echo "Not all elements in array were type integer.";
}

Checking if Any Item in Array is Found in a String

I know this question has been asked before but I haven't been able to get the provided solutions to work.
I'm trying to check if the words in an array match any of the words (or part of the words) in a provided string.
I currently have the following code, but it only works for the very first word in the array. The rest of them always return false.
"input" would be the "haystack" and "value" would be the "needle"
function check($array) {
global $input;
foreach ($array as $value) {
if (strpos($input, $value) !== false) {
// value is found
return true;
} else {
return false;
}
}
}
Example:
$input = "There are three";
if (check(array("one","two","three")) !== false) {
echo 'This is true!';
}
In the above, a string of "There is one" returns as true, but strings of "There are two" or "There are three" both return false.
If a solution that doesn't involve having to use regular expressions could be used, that would be great. Thanks!
The problem here is that check always returns after the first item in $array. If a match is found, it returns false, if not, it returns true. After that return statement, the function is done with and the rest of the items will not be checked.
function check($array) {
global $input;
foreach($array as $value) {
if(strpos($input, $value) !== false) {
return true;
}
}
return false;
}
The function above only returns true when a match is found, or false when it has gone through all the values in $array.
strpos(); is totally wrong here, you should simply try
if ($input == $value) {
// ...
}
and via
if ($input === $value) { // there are THREE of them: =
// ...
}
you can even check if the TYPE of the variable is the same (string, integer, ...)
a more professional solution would be
in_array();
which checks for the existance of the key or the value.
The problem here is that you're breaking out of the function w the return statement..so u always cut out after the first comparison.
you should use in_array() to compare the array values.
function check($array) {
global $input;
foreach ($array as $value) {
if (in_array($value,$input))
{
echo "Match found";
return true;
}
else
{
echo "Match not found";
return false;
}
}
}
You're returning on each iteration of $array, so it will only run once. You could use stristr or strstr to check if $value exists in $input.
Something like this:
function check($array) {
global $input;
foreach ($array as $value) {
if (stristr($input, $value)) {
return true;
}
}
return false;
}
This will then loop through each element of the array and return true if a match is found, if not, after finishing looping it will return false.
If you need to check if each individual item exists in $input you'd have to do something a little bit different, something like:
function check($array) {
global $input;
$returnArr = array();
foreach ($array as $value) {
$returnArr[$value] = (stristr($input, $value)) ? true : false;
}
return $returnArr;
}
echo '<pre>'; var_dump(check($array, $input)); echo '</pre>';
// outputs
array(3) {
["one"]=>
bool(false)
["two"]=>
bool(false)
["three"]=>
bool(true)
}
The reason your code doesnt work, is because you are looping through the array, but you are not saving the results you are getting, so only the last result "counts".
In the following code I passed the results to a variable called $output:
function check($array) {
global $input;
$output = false;
foreach ($array as $value) {
if (strpos($input, $value) != false) {
// value is found
$output = true;
}
}
return $output;
}
and you can use it like so:
$input = "There are two";
$arr = array("one","two","three");
if(check($arr)) echo 'this is true!';

Categories