Checking if value exists in array with array_search() - php

If 0 could be a possible key returned from array_search(), what would be the best method for testing if an element exists in an array using this function (or any php function; if there's a better one, please share)?
I was trying to do this:
if(array_search($needle, $haystack)) //...
But that would of course return false if $needle is the first element in the array. I guess what I'm asking is is there some trick I can do in this if statement to get it to behave like I want it? I tried doing these, but none of them worked:
$arr = array(3,4,5,6,7);
if(array_search(3, $arr) != false) //...
if(array_search(3, $arr) >= 0) //...
Appreciate the help.

This is the way:
if(array_search(3, $arr) !== false)
Note the use of the === PHP operator, called identical (not identical in this case). You can read more info in the official doc. You need to use it because with the use of the equal operator you can't distinguish 0 from false (or null or '' as well).
A better solution if you find the match and want to use the integer value is:
if (($pos = array_search(3, $arr)) !== false)
{
// do stuff using $pos
}

As an alternative to === and !==, you can also use in_array:
if (in_array($needle, $haystack))

As an alternative to ===, !==, and in_array(), you can use array_flip():
$arr = [3,4,5,6,7];
$rra = array_flip($arr);
if( $rra[3] !== null ):
var_dump('Do something, '.$rra[3].' exists!');
endif;
This is not fewer lines than the accepted answer. But it does allow you to get position and existence in a very human-readable way.
We want to find out if int 3 is in $arr, the original array:
array (size=5)
0 => int 3
1 => int 4
2 => int 5
3 => int 6
4 => int 7
array_flip creates a new array ($rra) with swapped key-value pairs:
array (size=5)
3 => int 0
4 => int 1
5 => int 2
6 => int 3
7 => int 4
Now we can verify the existence of int 3, which will (or will not be) a key in $rra with array_key_exists, isset, or by enclosing $rra[3]` in an if statement.
Since the value we are looking for could have an array key id of 0, we need to compare against null and not rely on evaluating 0 to false.
You can also make changes to the original array, should that be the use case, because if $rra[3] isn't null, $rra[3] will return what is the key (position 0, in this case) for the value in the original array.
if ( $rra[3] !== null ):
// evaluates to: unset( $array[0] );
unset( $arr[ $rra[3] ] );
endif;
This operation works just as well if you're working with an associative array.

Related

Filter array to keep elements where the key exists in the value string

I need to filter my flat, associative array of string-type values by checking if its key is found (case-sensitive) in its value as a substring. In other words, if an element's key is in the element's value, I want to retain the element in the output array.
I can craft a classic foreach() loop with calls of strpos(), but this feels very pedestrian. Is there a more modern/elegant way do this?
My code:
$array = [
'needle' => 'needle in haystack text',
'Need' => 'another needle',
'fine' => 'refined',
'found' => 'Foundation',
'' => 'non-empty haystack',
'missing' => 'not here',
'This is 0 in a haystack!',
];
$result = [];
foreach ($array as $needle => $haystack) {
if (strpos($haystack, $needle) !== false) {
$result[$needle] = $haystack;
}
}
var_export($result);
Output:
array (
'needle' => 'needle in haystack text',
'fine' => 'refined',
'' => 'non-empty haystack',
0 => 'This is 0 in a haystack!',
)
From PHP5.6, array_filter() gained the ARRAY_FILTER_USE_BOTH flag. This makes array_filter() an equivalent functional-style technique.
Code: (Demo)
var_export(
array_filter(
$array,
function($haystack, $needle) {
return strpos($haystack, $needle) !== false;
},
ARRAY_FILTER_USE_BOTH
)
);
One advantage of this is that $result doesn't need to be declared. On the other hand, despite the fact that it can technically be written as a one-liner, it would make a very long line of code -- something that puts the code near or over the soft character limit per line according to PSR-12 coding standards. So there is very little to compel you to change your code so far.
The good news is that PHP8 introduced str_contains() specifically to offer a clean, native, case-sensitive function to replace strpos() and its obligatory strict boolean false check.
Code: (Demo)
var_export(
array_filter($array, 'str_contains', ARRAY_FILTER_USE_BOTH)
);
This returns the same desired output, is a functional-style, one-liner, and concisely spans just 59 characters. I would recommend this approach.
To understand what is happening, the verbose syntax with array_filter() where str_contains() is not called by its string name looks like this:
var_export(
array_filter(
$array,
fn($haystack, $needle) => str_contains($haystack, $needle),
ARRAY_FILTER_USE_BOTH
)
);

PHP Group tabels [duplicate]

If 0 could be a possible key returned from array_search(), what would be the best method for testing if an element exists in an array using this function (or any php function; if there's a better one, please share)?
I was trying to do this:
if(array_search($needle, $haystack)) //...
But that would of course return false if $needle is the first element in the array. I guess what I'm asking is is there some trick I can do in this if statement to get it to behave like I want it? I tried doing these, but none of them worked:
$arr = array(3,4,5,6,7);
if(array_search(3, $arr) != false) //...
if(array_search(3, $arr) >= 0) //...
Appreciate the help.
This is the way:
if(array_search(3, $arr) !== false)
Note the use of the === PHP operator, called identical (not identical in this case). You can read more info in the official doc. You need to use it because with the use of the equal operator you can't distinguish 0 from false (or null or '' as well).
A better solution if you find the match and want to use the integer value is:
if (($pos = array_search(3, $arr)) !== false)
{
// do stuff using $pos
}
As an alternative to === and !==, you can also use in_array:
if (in_array($needle, $haystack))
As an alternative to ===, !==, and in_array(), you can use array_flip():
$arr = [3,4,5,6,7];
$rra = array_flip($arr);
if( $rra[3] !== null ):
var_dump('Do something, '.$rra[3].' exists!');
endif;
This is not fewer lines than the accepted answer. But it does allow you to get position and existence in a very human-readable way.
We want to find out if int 3 is in $arr, the original array:
array (size=5)
0 => int 3
1 => int 4
2 => int 5
3 => int 6
4 => int 7
array_flip creates a new array ($rra) with swapped key-value pairs:
array (size=5)
3 => int 0
4 => int 1
5 => int 2
6 => int 3
7 => int 4
Now we can verify the existence of int 3, which will (or will not be) a key in $rra with array_key_exists, isset, or by enclosing $rra[3]` in an if statement.
Since the value we are looking for could have an array key id of 0, we need to compare against null and not rely on evaluating 0 to false.
You can also make changes to the original array, should that be the use case, because if $rra[3] isn't null, $rra[3] will return what is the key (position 0, in this case) for the value in the original array.
if ( $rra[3] !== null ):
// evaluates to: unset( $array[0] );
unset( $arr[ $rra[3] ] );
endif;
This operation works just as well if you're working with an associative array.

Does not equal performing opposite in a foreach loop

I have an array that looks something like
array (size=7)
'car_make' => string 'BMW' (length=3)
'car_model' => string 'M3' (length=2)
'car_year' => string '2001' (length=4)
'car_price' => string '10000' (length=5)
'car_kilometers' => string '100000' (length=6)
'paint' => string 'black' (length=5)
'tires' => string 'pirelli' (length=7)
So basically there are a few base items in it that start with car_ and then a few extras.
I'm trying to search for each key that isn't car_* so paint and tires in this case. So I'm doing something like
foreach($_SESSION['car'][0] as $key=>$value)
{
if($key != preg_match('/car_.*/', $key))
{
echo 'Match';
}
}
Which I expected to echo out 2 Matches because of the 2 non car_ keys. Instead, this echos out 5 for the car_ keys.
But when I do
if($key == preg_match('/car_.*/', $key))
It echoes out 2 Matches for the 2 non car_ keys.
Where am I messing up or misunderstanding?
preg_match docs say about its return values:
preg_match() returns 1 if the pattern matches given subject, 0 if it does not, or FALSE if an error occurred.
So this wouldn't have worked in the first place.
I would use:
if ( substr($key, 0, 4) === "car_" )
...which is much less expensive as an operation than preg_match anyway.
According the documentation preg_match returns true when matching and false when not. So it appears that you are having some fun with PHP's type casting.
So rather than comparing the value you should check
if(true === preg_match('/car_.*/', $key))
This should take care of it.
Also, per the documentation:
Do not use preg_match() if you only want to check if one string is
contained in another string. Use strpos() or strstr() instead as they
will be faster.
Which would be:
if(false === str_pos('car_', $key))
From http://php.net/manual/en/function.preg-match.php
Return Values
preg_match() returns 1 if the pattern matches given subject, 0 if it
does not, or FALSE if an error occurred.
So you should compare it to 1 or to 0, not to a string.
The reason why your code was working but backwards is because comparing a number to a string produces interesting results:
From http://php.net/manual/en/types.comparisons.php
1 == "" is FALSE
0 == "" is TRUE

in_array check for non false values

$array = array(
'vegs' => 'tomatos',
'cheese' => false,
'nuts' => 765,
'' => null,
'fruits' => 'apples'
);
var_dump(in_array(false, $array, true)); //returns true because there is a false value
How to check strictly if there is at least one NON-false (string, true, int) value in array using in_array only or anything but not foreach?
var_dump(in_array(!false, $array, true)); //this checks only for boolean true values
var_dump(!in_array(false, $array, true)); //this returns true when all values are non-false
Actual solution below
Just put the negation at the right position:
var_dump(!in_array(false, $array, true));
Of course this will also be true if the array contains no elements at all, so what you want is:
var_dump(!in_array(false, $array, true) && count($array));
Edit: forget it, that was the answer for "array contains only values that are not exactly false", not "array contains at least one value that is not exactly false"
Actual solution:
var_dump(
0 < count(array_filter($array, function($value) { return $value !== false; }))
);
array_filter returns an array with all values that are !== false, if it is not empty, your condition is true.
Or simplified as suggested in the comments:
var_dump(
(bool) array_filter($array, function($value) { return $value !== false; })
);
Of course, the cast to bool also can be omitted if used in an if clause.
How to check strictly if there is at least one NON-false (string,
true, int) value in array using in_array only or anything but not
foreach?
This is not possible because:
String: this data type can contain any value, its not like boolean (true or false) or NULL.
INT: same as string, how to check for unknown?
Boolean: possible.
NULL: possible.
Then, INT and STRING data types can't be found just using an abstract (int) or (string)!
EDIT:
function get_type($v)
{
return(gettype($v));
}
$types = array_map("get_type", $array);
print_r($types);
RESULT:
Array
(
[vegs] => string
[cheese] => boolean
[nuts] => integer
[] => NULL
[fruits] => string
)

Eliminate Partial Strings from Array of Strings PHP

I can do this, I'm just wondering if there is a more elegant solution than the 47 hacked lines of code I came up with...
Essentially I have an array (the value is the occurrences of said string);
[Bob] => 2
[Theresa] => 3
[The farm house] => 2
[Bob at the farm house] => 1
I'd like to iterate through the array and eliminate any entries that are sub-strings of others so that the end result would be;
[Theresa] => 3
[Bob at the farm house] => 1
Initially I was looping like (calling this array $baseTags):
foreach($baseTags as $key=>$count){
foreach($baseTags as $k=>$c){
if(stripos($k,$key)){
unset($baseTags[$key]);
}
}
}
I'm assuming I'm looping through each key in the array and if there is the occurrence of that key inside another key to unset it... doesn't seem to be working for me though. Am I missing something obvious?
Thank you in advance.
-H
You're mis-using strpos/stripos. They can return a perfectly valid 0 if the string you're searching for happens to be at the START of the 'haystack' string, e.g. your Bob value. You need to explicitly test for this with
if (stripos($k, $key) !== FALSE) {
unset(...);
}
if strpos/stripos don't find the needle, they return a boolean false, which under PHP's normal weak comparison rules is equal/equivalent to 0. Using the strict comparison operators (===, !==), which compare type AND value, you'll get the proper results.
Don't forget as-well as needing !== false, you need $k != $key so your strings don't match themselves.
You have two problems inside your code-example:
You combine each key with each key, so not only others, but also itself. You would remove all entries so because "Bob" is a substring of "Bob", too.
stripos returns false if not found which can be confused with 0 that stands for found at position 0, which is also equal but not identical to false.
You need to add an additional check to not remove the same key and then fix the check for the "not found" case (Demo):
$baseTags = array(
'Bob' => 2,
'Theresa' => 3,
'The farm house' => 2,
'Bob at the farm house' => 1,
);
foreach ($baseTags as $key => $count)
{
foreach ($baseTags as $k => $c)
{
if ($k === $key)
{
continue;
}
if (false !== stripos($k, $key))
{
unset($baseTags[$key]);
}
}
}
print_r($baseTags);
Output:
Array
(
[Theresa] => 3
[Bob at the farm house] => 1
)

Categories