php recursive function doesn't work - php

I have a problem to understand why this doesn't work. I have recursive function who check if value in multidimensional array exists.
Then I have get_teams() function from which I want to return only unique values. I check for unique values with my find_value() function but it still return all the values.. Can someone explain me what happens? Thanks in advance
function find_value( $array, $searched_val ) {
foreach ( $array as $key => $val ) {
if ( $val === $searched_val ) {
return true;
}
if ( is_array( $val ) ) {
return find_value( $val, $searched_val );
}
}
return 0;
}
get_teams();
function get_teams() {
$people = get_data( 'some/file.json' );
$teams = [];
foreach ( $people as $person ) {
if ( ! find_value( $teams, $person['team'] ) ) {
$teams[] = [ 'text' => $person['team'] ];
}
}
return $teams;
}
This is sample input
Array
(
[0] => Array
(
[id] => 1
[name] => Friedrich Robel
[team] => WordPress
[position] => Frontend Developer
[salary] => 4400
)
[1] => Array
(
[id] => 2
[name] => Mr. Christop Veum
[team] => HTML
[position] => Manager
[salary] => 1200
)
[2] => Array
(
[id] => 3
[name] => Demarco Rippin
[team] => HTML
[position] => QA
[salary] => 4400
)
[3] => Array
(
[id] => 4
[name] => Felicia Farrell
[team] => HTML
[position] => QA
[salary] => 1200
)
[4] => Array
(
[id] => 5
[name] => Torrance Fritsch
[team] => HTML
[position] => Assistant Manager
[salary] => 2500
)
[5] => Array
(
[id] => 6
[name] => Erica Daugherty
[team] => Mail
[position] => Assistant Manager
[salary] => 500
)
)
And I want this output
Array
(
[0] => WordPress,
[1] => HTML,
[2] => Mail
)

Your problem is that you returns the result of the sub-search without testing it.
Instead of return find_value(...), you have to test its value.
function find_value( $array, $searched_val ) {
foreach ( $array as $key => $val ) {
if ( $val === $searched_val ) {
return true;
}
if ( is_array( $val ) ) {
// Here, you have to test the result before to return TRUE.
if (find_value( $val, $searched_val )) {
return true ;
}
}
}
return 0;
}

The fix is, as Syscall posted, to test the return of find_value(), and only return if it is true.
As your code is structured now, it will return either true or false from the recursion call, which will always be required, since you are storing your values as [ 'text' => $person['team'] ];
The way your code is designed, with the return 0 outside the foreach is only to return false in the case a match was not found. For this reason, returning a false from the contents of that conditional is premature. Your loop does not have a chance to iterate and test all the values of the passed array. This early returning results in duplicate array entries.
In any case, the results at the end will be an array of ['text' => '<job>'] array members. If you want only the job string, assign like this instead:
$teams[] = $person['team'];
If you make this change, the other is not required. Note that it also removes the need for recursion, as $teams will contain only an array of strings.

Related

How to use array_in with multidimensional array in php

I have a array in below format
Array ([abc] => Array ( [0] => Array ( [abc_id] => 10 [status] => true ) [1] =>
Array ( [abc_id] => 11 [status] => true ) [2] => Array ( [abc_id] => 12 [status] => true ) )
[pqr] => Array ( ) [xyz] => Array ( [0] => Array ( [xyz_id] => 8 [status] => false )
[1] => Array ( [xyz_id] => 9 [status] => false ) ) [mno] => Array ( ) [def] => Array ( ) [unit_id] => 1)
And I want to check if there is a status = false word in the entire array.
I tried using array_in but couldn't succeed. Can anyone give me some proper solution for the above issue? Is there any other way to check if the array includes false anywhere.
You can use array_walk_recursive() which will go through all levels of a multidimensional array - BUT only the leaf nodes. Although that is fine as that is what you want.
This code has a found flag and a simple function which checks the label and the value for the values your after and sets the flag to be true if they both match...
$found = false;
array_walk_recursive($aray, function ($item, $key) use (&$found) {
if ( $key === "status" && $item == false) {
$found = true;
}
});
echo $found;

Get value from array using key

I have an array like this:
Array
(
[0] => Array
(
[settingID] => 1
[name] => audioCueDistance
[setValue] => false
)
[1] => Array
(
[settingID] => 2
[name] => audioCueDistanceToGo
[setValue] => true
)
[2] => Array
(
[settingID] => 3
[name] => audioCues
[setValue] => true
)
[3] => Array
(
[settingID] => 4
[name] => audioCueStyle
[setValue] => default
)
[4] => Array
(
[settingID] => 5
[name] => audioCueTime
[setValue] => true
)
[5] => Array
(
[settingID] => 6
[name] => isMetric
[setValue] => true
)
How can I get individual values from key for example, I would like to output the setValue of isMetric.
Thanks
foreach ($foo as $bar) {
if ($bar['name'] == "isMetric") {
// Use setValue here
}
}
From what I understand you want to do something like $myArray['isMetric']['setValue'].
As your array is not in that form you need to map it that way.
$myArray = array(
array(
'settingID'=>6,
'name'=>'isMetric',
'value'=>true
)
);
$myAssocArray = array_reduce($myArray, function($carry, $item){
$carry[$item['name']] = $item;
return $carry;
}, array());
echo $myAssocArray['isMetric']['setValue'];
Run this code here: https://repl.it/CZ3R
foreach($array as $element)
{
if($element['name'] = 'isMetric')
return $element['setValue'];
}
throw new \Exception('isMetric Not Found.');

Search value in multidimension array and keep keys association

I have this array converted from xml of webservice. I have 500 items in this array.
I want to search any value and return all found array items with key association ( similar to database select query ). So if I search 'dummy' then it should return first item of this array.
Array
(
[12.12.2014] => Array
(
[7] => Array
(
[id] => 1672
[date] => 12.12.2014
[description] => rummy dummy data
[room] => delux
[Type] => garden
[from] => 17:00
[to] => 17:45
[assets] => Array
(
[asset] => Array
(
[0] => Array
(
[number] => 5275
[detail] => primary one
)
[1] => Array
(
[number] => 19
[detail] => secondary one
)
)
)
[references] => Array
(
[reference] => Array
(
[personnumber] => 479470
[type] => worker
[name] => David
[department] => Sales
[cv] => Array
(
[pdetails] => follow later
)
[profile] => True
)
)
)
)
[13.12.2014] => Array
(
[17] => Array
(
[id] => 1672
[date] => 13.12.2014
[description] => brown fox jump
[room] => star
[Type] => city
[from] => 17:00
[to] => 17:45
[assets] => Array
(
[asset] => Array
(
[number] => 5275
[detail] => prime two
)
)
[references] => Array
(
[reference] => Array
(
[personnumber] => 479470
[type] => manager
[name] => Albert
[department] => Purchase
[cv] => Array
(
[pdetails] => follow later
)
[profile] => True
)
)
)
)
)
I tried stripos to search string in array value and in_array based functions but either it gives incorrect result or key association is not maintained.
I am unable to find a way to maintain key->value.
function search($array, $key, $value)
{
$results = array();
if (is_array($array))
{
if (isset($array[$key]) && $array[$key] == $value)
$results[] = $array;
foreach ($array as $subarray)
$results = array_merge($results, search($subarray, $key, $value));
}
return $results;
}
This may be worst function you have ever seen but this do the job. If some one can make it recursive ( array may be further deeper ).
function search_in_multi_array($srchvalue, $array)
{
$foundkey = '';
if (is_array($array) && count($array) > 0)
{
foreach($array as $pkey => $pvalue)
{
foreach($pvalue as $ckey => $cvalue)
{
if (is_array($cvalue) && count($cvalue) > 0)
{
if(in_array($srchvalue,$cvalue))
{
$foundkey[$pkey][$ckey] = $cvalue;
}
foreach($cvalue as $dkey => $dvalue)
{
if(!is_array($dvalue))
{
$pos = stripos($dvalue, $srchvalue);
if ($pos !== false)
{
$foundkey[$pkey][$ckey] = $cvalue;
}
}
}
}
}
}
}
return $foundkey;
}
Function call -
$needle = 'fox';
search_in_multi_array($needle, $my_array);
This is the output
Array
(
[13.12.2014] => Array
(
[17] => Array
(
[id] => 1672
[date] => 13.12.2014
[description] => brown fox jump
[room] => star
[Type1] => city
[from] => 17:00
[to] => 17:45
[assets] => Array
(
[asset] => Array
(
[number] => 5275
[detail] => prime two
)
)
[references] => Array
(
[reference] => Array
(
[personnumber] => 479470
[Type1] => manager
[name] => Albert
[department] => Purchase
[cv] => Array
(
[pdetails] => follow later
)
[profile] => 1
)
)
)
)
)
You can use array_search() function to look through the array values. But array_search only looks in single-dimensional array.
Since you have a multi-dimensional array, you can write custom recursive function to search recursively in the array
function recursive_array_search($needle,$haystack) {
foreach($haystack as $key=>$value) {
$current_key=$key;
if($needle===$value OR (is_array($value) && recursive_array_search($needle,$value) !== false)) {
return $current_key;
}
}
return false;
}
But please note, using array_search() is a easier approach but not a optimised function. Which means if you're more concerned about your memory utilisation then I would also addtionally suggest.
Create a new array say 'dictionary' and store them like
$dictonary[<key-searched>] = array('12.12.2014', '13.12.2014')
So you process them once, and cache them
So next time when you want search again for the same key, you can first check if the key exists in dictionary. If exists return from there, else use array_search and cache the results in dictionary
Its always easier to search by key-value than to search in a multi-dimensional array.
I've made a simple routine that will extract the values in the array you're looking for:
function search_keys($needle,$haystack)
{
foreach($haystack as $key => $value)
{
if (is_array($value)) $output[$key] = search_keys($needle,$value);
else if (strpos($value,$needle) !== FALSE) $output[$key] = $value;
}
return isset($output) ? $output : NULL; // prevent warning
}
echo '<pre>';
print_r(search_keys('garden',$data));
echo '</pre>';
This will return 'garden' as:
Array
(
[12.12.2014] => Array
(
[7] => Array
(
[Type] => garden
)
)
)
You can further process the output of this function, or change the function, as needed.
You may want to have a look at XPath to run queries against the "raw" XML, see DOMXPath for example.
Something like /myRootTag/someDayTag[.//text()[contains(.,'MY_SEARCH_VALUE')]] should do the trick, selecting and returning all the someDayTag XML elements below the myRootTag which have the text MY_SEARCH_VALUE in any child node.

Get values (plural) from multi-dimensional array with key

I know the key, now I need ALL of the results that would yield when I search the 5000+ user database. Any user may have none, one or multiple locations, identified by an id and name field. Therefore I need the results in an array, not just the first/last one, but all of them. Below is an example of a user (actual array setup, fake data ;) )
Array
(
[ID] => 2
[user_login] => SomeGuy
[user_pass] => GreatEncryptedPassword
[user_nicename] => Some Guy
[user_email] => someguy#has-email.com
[user_url] => someguy.com
[user_registered] => 2013-04-11 11:18:58
[user_activation_key] =>
[user_status] => 0
[display_name] => Some Guy
[umeta_id] => 31
[user_id] => 2
[meta_key] => facebookmeta
[meta_value] => Array
(
[id] => 1234567890
[name] => Some Guy
[first_name] => Some
[last_name] => Guy
[link] => http://www.facebook.com/someguy
[username] => someguy
[birthday] => 02/21/1983
[location] => Array
(
[id] => 108276092536515 //actual ID, try at facebook.com/108276092536515
[name] => Arnhem, Netherlands
)
[gender] => male
[relationship_status] => In a Relationship
[significant_other] => Array
(
[name] => Some Chick
[id] => 12345678906789
)
[email] => someguy#has-email.com
[timezone] => 2
[locale] => nl_NL
[verified] => 1
[updated_time] => 2013-04-02T09:28:30+0000
)
)
As you can make out, this guy has 1 location in his facebook data, but other locations include the same [location] => Array ( [id] => 123 [name] => SomePlace ) for example for [work] or [education], or, or, or...
I've tried a recursive function like this:
function get_value_by_key( $array, $key ){
foreach( $array as $k => $each ){
if( $k == $key ){
return $each;
}
if( is_array( $each )){
if( $return = get_value_by_key($each,$key)){
return $return;
}
}
}
}
print_r( get_value_by_key( $users, 'location' );
How can I modify the above function to return an array of location arrays? This one return the above data of the first user containing a location, not the location itself or an array of them.
EDIT:
What I need as a result is something like this:
Array(
[0] => Array(
[id] => 1234567890
[name] => GreatCity, World
)
[1] => Array(
[id] => 2345678901
[name] => SomeCity, Blop
)
[2] => Array(
[id] => 3456789012
[name] => AnotherCity, Boo
)
)
Edit based on answer
Answer from Thomas David Plat gives me the correct results, but still a not very usable data structure. How to get the results out of the structure and into that shown in the above edit?
Results from David's answer:
Array
(
[0] => Array
(
[0] => Array
(
[0] => Array
(
[id] => 108276092536515
[name] => Arnhem, Netherlands
)
[1] => Array()
)
)
[1] => Array
(
[0] => Array
(
[0] => Array
(
[id] => 108276092536515
[name] => Arnhem, Netherlands
)
[1] => Array()
)
)
[2] => Array()
[3] => Array()
[4] => Array()
I've tried variations of array_filter, array_map, array_values and others like below:
$locations = array_map( 'array_filter', find_array_values( $users, 'location' ));
But the structure seems to stay...
UPDATED ANSWER
$matches = array();
function find_array_values($haystack, $needle)
{
global $matches;
$collection = array();
foreach($haystack AS $key => $value)
{
if($key === $needle)
{
$matches[] = $value;
}
else if(is_array($value))
{
find_array_values($value, $needle);
}
}
}
find_array_values($array, 'location');
print_r($matches);
?>
This will work, but as I already said in the comments it's a bad practice since it uses the global keyword. If you implement this function as a method into a class, instead of using the global keyword you could use a class variable which would be a neat solution.
OLD Answer
function find_array_values($haystack, $needle)
{
$collection = array();
foreach($haystack AS $key => $value)
{
if($key === $needle)
{
$collection[] = $value;
}
else if(is_array($value))
{
$collection[] = find_array_values($value, $needle);
}
}
return $collection;
}
echo "<pre>";
print_r(find_array_values($users, 'location'));
echo "</pre>";
Here you are. Just pass an array of your users into the function. The function will return an array of arrays of locations.
There's one restriction. The function will not search trough locations that are within locations.
you can modify ur location part of your array like this
[location] => Array
(
[work]=> Array(
[id] => 108276092536515
[name] => Arnhem, Netherlands
)
[home] => Array(
[id] => 108276092536515
[name] => Arnhem, Somewhere else
)
)
if you modify your array like this then your function will return array of arrays for location

Search an Array with nested arrays and return

The Array format
Array
(
[76ea881ebe188f1a7e7451a9d7f17ada] => Array
(
[rowid] => 76ea881ebe188f1a7e7451a9d7f17ada
[id] => 1
[qty] => 2
[price] => 20
[name] => First
[options] => Array
(
[permName] => beer
)
[subtotal] => 40
)
[e7a36fadf2410205f0768da1b61156d9] => Array
(
[rowid] => e7a36fadf2410205f0768da1b61156d9
[id] => 3
[qty] => 6
[price] => 20
[name] => Second
[options] => Array
(
[permName] => achieve
)
[subtotal] => 120
)
Is there a way for me to search this array for the title or in this case lets say e7a36fadf2410205f0768da1b61156d9 and once it is found just return the price and the qty values?
Any help would be greatly appreciated.
You can you array_key_exists function to check if there is any element with a given key.
$title = 'e7a36fadf2410205f0768da1b61156d9';
if (array_key_exists($title, $arr)) {
return array('price'=>$arr[$title]['price'], 'qty'=>$arr[$title]['qty']);
}
$title = 'e7a36fadf2410205f0768da1b61156d9';
if (isset($arr[$title])) {
return array('price'=>$arr[$title]['price'], 'qty'=>$arr[$title]['qty']);
}
This function is enough.
function search_title($title, $array){
if(array_key_exists($array[$title])){
return array($array[$title]['price'],$array[$title]['qty']);
}else{
return array( false, false);
}
}
Usage,
list ($price, $qty) = search_title('e7a36fadf2410205f0768da1b61156d9', $array);
if($price!==false){
// search was successful
}

Categories