I'm working on a program that uses PHP's internal array pointers to iterate along a multidimensional array. I need to get an element from the current row, and I've been doing it like so:
$arr[key($arr)]['item']
However, I'd much prefer to use something like:
current($arr)['item'] // invalid syntax
I'm hoping there's a function out there that I've missed in my scan of the documentation that would enable me to access the element like so:
getvalue(current($arr), 'item')
or
current($arr)->getvalue('item')
Any suggestions?
I very much doubt there is such a function, but it's trivial to write
function getvalue($array, $key)
{
return $array[$key];
}
Edit: As of PHP 5.4, you can index array elements directly from function expressions, current($arr)['item'].
Have you tried using one of the iterator classes yet? There might be something in there that does exactly what you want. If not, you can likely get what you want by extending the ArrayObject class.
This function might be a bit lenghty but I use it all the time, specially in scenarious like:
if (array_key_exists('user', $_SESSION) === true)
{
if (array_key_exists('level', $_SESSION['user']) === true)
{
$value = $_SESSION['user']['level'];
}
else
{
$value = 'DEFAULT VALUE IF NOT EXISTS';
}
}
else
{
$value = 'DEFAULT VALUE IF NOT EXISTS';
}
Turns to this:
Value($_SESSION, array('user', 'level'), 'DEFAULT VALUE IF NOT EXISTS');
Here is the function:
function Value($array, $key = 0, $default = false)
{
if (is_array($array) === true)
{
if (is_array($key) === true)
{
foreach ($key as $value)
{
if (array_key_exists($value, $array) === true)
{
$array = $array[$value];
}
else
{
return $default;
}
}
return $array;
}
else if (array_key_exists($key, $array) === true)
{
return $array[$key];
}
}
return $default;
}
PS: You can also use unidimensional arrays, like this:
Value($_SERVER, 'REQUEST_METHOD', 'DEFAULT VALUE IF NOT EXISTS');
If this does not work, how is your multidimensional array composed? A var_dump() might help.
$subkey = 'B';
$arr = array(
$subkey => array(
'AB' => 'A1',
'AC' => 'A2'
)
);
echo current($arr[$subkey]);
next($arr[$subkey]);
echo current($arr[$subkey]);
I often use
foreach ($arr as $key=>$val) {
$val['item'] /*$val is the value of the array*/
$key /*$key is the key used */
}
instead of
next($arr)/current($arr)
Related
I have an array where each element has a subarray with multiple Ids. When looping through the array, I'd like to check if the subarray has any elements besides a given one.
For example, I'd like to echo 'Yes' whenever one of the subarrays has any ids other than 'TESTID'.
I can do this by looping through the subarray, but I'd like to know of a way that doesn't require double loops.
Here's the current code:
foreach ($elements as $element) {
...
if (besidesInArray('TESTID',$element['ids'])) {
//operations
} else {
//element only has 'TESTID'
}
...
}
...
function besidesInArray($needle, $haystack) {
foreach ($haystack as $hay) {
if($hay != $needle) {
return TRUE;
}
}
return FALSE;
}
While this code works, I'd like to see if there's a more elegant solution.
You can use in_array() function to achieve this
foreach($array as $key => $subarray)
{
if(in_array("TESTID", $subarray))
{
//found
} else {
//not found
}
}
preg_grep for TESTID but invert the grep so that it returns entries NOT matching.
foreach($array as $subarray) {
if(preg_grep("/TESTID/", $subarray, PREG_GREP_INVERT)) {
echo 'Yes'; //others found
}
}
TESTID could be a var instead. Man I love some preg_grep!
find = implode(')|(',$mypatternarray);
find.="(".find.")";
foreach($subarray as $subar){
if(preg_match("find",$subar)>0)){
echo "id found";
}
}
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;
}
private function find($needle, $haystack) {
foreach ($haystack as $name => $file) {
if ($needle == $name) {
return $file;
} else if(is_array($file)) { //is folder
return $this->find($needle, $file); //file is the new haystack
}
}
return "did not find";
}
Hey, this method searches for a specific key in an associative array and returns the value associated with it. There's some problem with the recursion. Any clue?
Maybe it's overkill, but it's funny to use RecursiveIterators :)
UPDATE: Maybe it was overkill with old versions of PHP, but with >=5.6 (specially with 7.0) I would totally use this without doubt.
function recursiveFind(array $haystack, $needle)
{
$iterator = new RecursiveArrayIterator($haystack);
$recursive = new RecursiveIteratorIterator(
$iterator,
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($recursive as $key => $value) {
if ($key === $needle) {
return $value;
}
}
}
UPDATE: Also, as of PHP 5.6, with generators you can easily iterate over all elements which pass the filter, not only the first one:
function recursiveFind(array $haystack, $needle)
{
$iterator = new RecursiveArrayIterator($haystack);
$recursive = new RecursiveIteratorIterator(
$iterator,
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($recursive as $key => $value) {
if ($key === $needle) {
yield $value;
}
}
}
// Usage
foreach (recursiveFind($haystack, $needle) as $value) {
// Use `$value` here
}
function array_search_key( $needle_key, $array ) {
foreach($array AS $key=>$value){
if($key == $needle_key) return $value;
if(is_array($value)){
if( ($result = array_search_key($needle_key,$value)) !== false)
return $result;
}
}
return false;
}
this will work !
you need to stop the recursive deep search, by return false and then check it in the function.
you can find more examples of functions (like using RecursiveArrayIterator and more) in this link :
http://php.net/manual/en/function.array-search.php
The answer provided by xPheRe was extremely helpful, but didn't quite solve the problem in my implementation. There are multiple nested associative arrays in our data structure, and there may be multiple occurrences of any given key.
In order to suit our purposes, I needed to implement a holder array that was updated while traversing the entire structure, instead of returning on the first match. The real work was provided by another poster, but I wanted to say thanks and share the final step that I had to cover.
public function recursiveFind(array $array, $needle)
{
$iterator = new RecursiveArrayIterator($array);
$recursive = new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::SELF_FIRST);
$aHitList = array();
foreach ($recursive as $key => $value) {
if ($key === $needle) {
array_push($aHitList, $value);
}
}
return $aHitList;
}
try this:
array_walk_recursive(
$arrayToFindKey,
function($value, $key, $matchingKey){
return (strcasecmp($key, $matchingKey) == 0)? true : false;
}
, 'matchingKeyValue'
);
The best solution above misses the case if the key is repeated and only returns the first value, here I get all the values in an array instead:
function recursiveFind(array $array, $needle) {
$iterator = new RecursiveArrayIterator($array);
$recursive = new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::SELF_FIRST);
$return = [];
foreach ($recursive as $key => $value) {
if ($key === $needle) {
$return[] = $value;
}
}
return $return;
}
I just been through a similar issue and here's what worked for me:
function searchArrayByKey($haystack, $needle, $i = 0) {
$result = array();
foreach($haystack as $key => $value) {
if (is_array($value)) {
$nextKey = searchArrayByKey($value, $needle);
if ($nextKey) {
return $nextKey;
}
}
if (is_array($value) && array_key_exists($needle, $value)) {
$result[$i++] = $value[$needle];
}
}
if (empty($result)) {
return false;
} else {
return $result;
}
}
This is going to return an array containing the value of all the matching keys it found in the multidimensional array. I tested this with arrays dinamically generated by an e-mail API. In the case of multiple matches, you just need to create a simple foreach loop to sort the array however you want.
I noticed the main mistake I was making was using if-ifelse conditions when I should be using if-if conditions. Any questions or criticism are very welcome, cheers!
I recently came across the same issue, when dealing with Yii2 query object.
The reason your function didn't work is that the return action doesn't work here. Just pass a reference parameter to store the value, and do whatever you want afterwards.
As you can see, this is a simple PHP function doesn't rely on any library. So I think its worth to mention with all the answer listed above.
function array_search_by_key_recursive($needle, array $haystack, &$return)
{
foreach ($haystack as $k => $v) {
if (is_array($v)) {
array_search_by_key_recursive($needle, $v, $return);
} else {
if($k === $needle){
$return = $v;
}
}
}
}
array_search_by_key_recursive($needle, array $haystack, $return);
print_r($return);
I have a unique case where I have an array like so:
$a = array('a' => array('b' => array('c' => 'woohoo!')));
I want to access values of the array in a manner like this:
some_function($a, array('a')) which would return the array for position a
some_function($a, array('a', 'b', 'c')) which would return the word 'woohoo'
So basically, it drills down in the array using the passed in variables in the second param and checks for the existence of that key in the result. Any ideas on some native php functions that can help do this? I'm assuming it'll need to make use of recursion. Any thoughts would be really appreciated.
Thanks.
This is untested but you shouldn't need recursion to handle this case:
function getValueByKey($array, $key) {
foreach ($key as $val) {
if (!empty($array[$val])) {
$array = $array[$val];
} else return false;
}
return $array;
}
You could try with RecursiveArrayIterator
Here is an example on how to use it.
Here’s a recursive implementation:
function some_function($array, $path) {
if (!count($path)) {
return;
}
$key = array_shift($path);
if (!array_key_exists($key, $array)) {
return;
}
if (count($path) > 1) {
return some_function($array[$key], $path);
} else {
return $array[$key];
}
}
And an iterative implementation:
function some_function($array, $path) {
if (!count($path)) {
return;
}
$tmp = &$array;
foreach ($path as $key) {
if (!array_key_exists($key, $tmp)) {
return;
}
$tmp = &$tmp[$key];
}
return $tmp;
}
These functions will return null if the path is not valid.
$a['a'] returns the array at position a.
$a['a']['b']['c'] returns woohoo.
Won't this do?
Why does the following code give me an error in php?:
$b = array("1" => "2")["1"];
Error I get is Parse error...
Help.
Unfortunately, in PHP, you need to do this:
$a = array("1" => "2");
$b = $a["1"];
It feels like your example should work because it does in other languages. But this is just the way PHP is.
Couple things. You can't pull immediately from arrays during creation, and keys of numerical values are automatically converted to integers, even if they're intended to be strings.
You can use a function to do this for you:
function Get($array, $key, $default = false)
{
if (is_array($array) === true)
{
settype($key, 'array');
foreach ($key as $value)
{
if (array_key_exists($value, $array) === false)
{
return $default;
}
$array = $array[$value];
}
return $array;
}
return $default;
}
And use it like this:
$b = Get(array("1" => "2"), "1"); // 2
If you don't need to access multi-dimensional arrays you can also use this shorter function:
function Get($array, $key, $default = false)
{
if (is_array($array) === true)
{
return (array_key_exists($value, $array) === true) ? $array[$value] : $default;
}
return $default;
}