path to array value deep multidimensional array - php

I have an array where I need the path (keys) to a given value. I've written a function for it but I can't get it working, the array can have an infinite depth to be controlled in another function, I haven't decided on a limit yet but the depth is variable, it actually works up to a point but the depth may be 30-40-50 deep so I need it to work that way, this function is really just for value identification, the numbers are templates, the tags are tags in the templates, each tag has a single template associated with it, all template names are unique and tags names aren't because they are only associated with a single template, id values are separated by a dash (illegal in template and tag ids), where template ids are only numeric and tag ids are wrapped with squigglies and a dollar sign like so {$TAG}, don't have to worry about duplicate values because infinite loops are forbidden (template can't link to itself or a template that links to itself) plus ids are given only to templates where template names are unique. The id of the template named 4 in the given array would be 0-{$CONTENT}-2-{$PARAGRAPH}-4, where I lose it is my function won't go beyond this depth, thanks for the help
array (size=1)
0 =>
array (size=4)
'{$TITLE}' => null
'{$NAME}' => null
'{$FRIENDS}' =>
array (size=1)
1 =>
array (size=2)
'{$friend}' => null
'{$friends[$i]}' => null
'{$CONTENT}' =>
array (size=1)
2 =>
'{$HEADING}' =>
array (size=1)
3 =>
array (size=0)
empty
'{$PARAGRAPH}' =>
array (size=1)
4 =>
array (size=1)
'{$AnotherParagraph}' => null
here is my function, I've added the depth variable just for testing purposes, $this->family is the array given above, calling the function: $id = $this->get_id(4);
public function get_id($member, $family=null, $id=null, $depth=0) {
if (empty($this->family)) {
return false;
}
if (is_null($family)) {
$family = $this->family;
}
foreach ($family as $parent => $tag_child) {
if ($member === $parent) {
return $member;
}
foreach ($tag_child as $tag => $child) {
if (is_null($child) || empty($child)) {
continue;
}
$childkey = key($child);
if ($member === $childkey) {
$id .= '-'.$parent.'-'.$tag.'-'.$member;
$id = ltrim($id, '-');
return $id;
}
$family = $child;
if (!is_null($id) && !empty($id)) {
$id_array = explode('-', $id);
foreach ($id_array as $id_value) {
if ($id_value !== $childkey) {
$new_id_array[] = $id_value;
}else{
break;
}
}
$id = implode('-', $new_id_array);
}
if ($parent === 0) {
$id = $parent.'-'.$tag.'-'.$childkey;
}else{
$id .= '-'.$tag.'-'.$childkey;
}
$id = ltrim($id, '-');
$depth++;
$id = $this->get_id($member, $family, $id, $depth);
}
}
}

Use a recursive function. Here's one I wrote for this EXACT purpose.
public function recurseArray($array, $builtKey = "") {
$values = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
if (!empty($builtKey)) {
$values = array_merge($values, recurseArray($value, $builtKey.".".$key));
} else {
$values = array_merge($values, recurseArray($value, $key));
}
} else {
if (!empty($builtKey)) {
$values[$builtKey.".".$key] = $value;
} else {
$values[$key] = $value;
}
}
}
return $values;
}
This results in a flat array that transforms this:
array(
"key" => array(
"of" => array(
"many" => array(
"depths" => "value"
)
)
),
"key2" => "value"
);
Into this:
array(
"key.of.many.depths" => "value",
"key2" => "value"
);

Related

Transform array recursively with parent and children

I want to transform an array of resources that can have an infinity of children to a simple array like below. I just want to keep the information of the parent, if there is a parent. In my context, a parent is the array just above the child array.
I have this array (bigger in reality with a lof of children), but each children may have an infinity of arrays children:
$array = array (
0 =>
array (
'#id' => 'Authorization',
'#sortOrder' => '1',
'resource' =>
array (
'#id' => 'Authorization2',
'#title' => 'Authorization2',
),
),
);
And I would like to get this, recursively :
$resources = [
0 => [
'parent' => null,
'resource' => 'Authorization'],
1 => [
'Authorization' => 'Authorization',
'resource' => 'Authorization2']
];
I tried this and I get every single resource but I can't get parents for resources that has one:
public function array_values_recursive($array) {
$flat = array();
foreach($array as $key => $value) {
if (is_array($value)) {
$flat = array_merge($flat, $this->array_values_recursive($value));
}
else {
if($key === '#id') {
$flat[]['value'] = $value;
}
}
}
return $flat;
}
That did the job for me, thanks #Sammitch for the idea.
public function array_values_recursive($array, $parent = null) {
$flat = array();
$i = 0;
foreach($array as $key => $value) {
if (is_array($value)) {
//we create a new parent
if(array_key_exists('#id',$array)){
$flat = array_merge($flat, $this->array_values_recursive($value, $array['#id']));
}
//we keep the last parent known
else{
$flat = array_merge($flat, $this->array_values_recursive($value, $parent));
}
}
else {
if($key === '#id') {
if($parent){
$flat[$i]['value'] = $value;
$flat[$i]['parent'] = $parent;
}
else{
$flat[$i]['value'] = $value;
}
$i++;
}
}
}
return $flat;
}

how to find key from any array php

I have a string, I need to know at what index is that string exist in the array. My array is as follows:
array(3)
{
[0]=>object(stdClass)#47170 (3)
{
["countries"]=>string(2) "HK"
["last_seen_date"]=>string(10) "2016-09-17"
["ad_uid"]=>string(14) "157d5908a1ca83"
}
[1]=>object(stdClass)#47171 (3)
{
["countries"]=>string(2) "HK"
["last_seen_date"]=>string(10) "2016-09-27"
["ad_uid"]=>string(14) "157d7978513bc3"
}
[2]=>object(stdClass)#47230 (3)
{
["countries"]=>string(2) "HK"
["last_seen_date"]=>string(10) "2016-09-27"
["ad_uid"]=>string(14) "157ea7239824e9"
}
}
The last seen date is:2016-09-27.
I would like to know at what index does 2016-09-27 exist in the array. So I know what is ad_uid related to that date. I have a method which does this.
public function getAd_uid($last_seen_date,$values){
$key = array_keys($values,$last_seen_date);
print_r($key);
}
The result gets an empty array. I have tried array_serach() has same empty results. Any other alternative solutions to achieve results?
To find all $ad_uids last_seen at particular date you can use array_filter which will return you all elements you are looking for. If you need ad_uids only, you can apply array_map to that array as following:
<?php
// $array is the array in question.
$filtered = array_filter($array, function($item) {
return $item->last_seen_date == "2016-09-27";
});
$ad_uids = array_map(function($item){return $item->ad_uid;}, $filtered);
Example
As each each entry of your array is an object and you know the attributs' names of theses objects (I assume they never change), I would do it like this :
/**
* #param string $last_seen_date
* #param array $values
* #return mixed null|int
*/
function getAdUid($last_seen_date, array $values) {
// Just in case no entry match
$matching_index = null;
// Loop through each entry: $entry is an object
foreach($values as $index => $entry) {
if($entry->last_seen_date == $last_seen_date) {
$matching_index = $index;
break; // end loop: we found that we are looking for
}
}
return $matching_index;
}
to do that just loop your array
foreach($values as $key => $row) {
// do something
}
then check if $last_seen_date is equal to the loop index last_seen_date $row->last_seen_date
if ($row->last_seen_date == $last_seen_date) {
return $key;
}
if it is just return it
return $key;
so your php code would be like this
$arr = array(
0 =>
(object)array(
"countries" => "HK",
"last_seen_date" => "2016-09-17",
"ad_uid"=> "157d5908a1ca83"
),
1 =>
(object)array(
"countries" => "HK",
"last_seen_date" => "2016-09-20",
"ad_uid" => "157d7978513bc3"
),
2 =>
(object)array(
"countries" => "HK",
"last_seen_date" => "2016-09-26",
"ad_uid" => "157ea7239824e9"
)
);
function getAd_uid($last_seen_date, $values){
foreach($values as $key => $row) {
if ($row->last_seen_date == $last_seen_date) {
return $key;
}
}
}
echo '2016-09-17 is on index => '.getAd_uid('2016-09-17', $arr).'<br>';
echo '2016-09-20 is on index => '.getAd_uid('2016-09-20', $arr).'<br>';
echo '2016-09-26 is on index => '.getAd_uid('2016-09-26', $arr).'<br>';
RESULT
Working Demo

Get corresponding array values from same index [duplicate]

using array_search in a 1 dimensional array is simple
$array = array("apple", "banana", "cherry");
$searchValue = "cherry";
$key = array_search($searchValue, $array);
echo $key;
but how about an multi dimensional array?
#RaceRecord
[CarID] [ColorID] [Position]
[0] 1 1 3
[1] 2 1 1
[2] 3 2 4
[3] 4 2 2
[4] 5 3 5
for example i want to get the index of the car whose position is 1. How do i do this?
In php 5.5.5 & later versions,
you can try this
$array_subjected_to_search =array(
array(
'name' => 'flash',
'type' => 'hero'
),
array(
'name' => 'zoom',
'type' => 'villian'
),
array(
'name' => 'snart',
'type' => 'antihero'
)
);
$key = array_search('snart', array_column($array_subjected_to_search, 'name'));
var_dump($array_subjected_to_search[$key]);
Output:
array(2) { ["name"]=> string(5) "snart" ["type"]=> string(8) "antihero" }
working sample : http://sandbox.onlinephpfunctions.com/code/19385da11fe0614ef5f84f58b6dae80bd216fc01
Documentation about array_column can be found here
function find_car_with_position($cars, $position) {
foreach($cars as $index => $car) {
if($car['Position'] == $position) return $index;
}
return FALSE;
}
You can try this
array_search(1, array_column($cars, 'position'));
Hooray for one-liners!
$index = array_keys(array_filter($array, function($item){ return $item['property'] === 'whatever';}))[0];
Let's make it more clear:
array_filter(
$array,
function ($item) {
return $item['property'] === 'whatever';
}
);
returns an array that contains all the elements that fulfill the condition in the callback, while maintaining their original array keys. We basically need the key of the first element of that array.
To do this we wrap the result in an array_keys() call and get it's first element.
This specific example makes the assumption that at least one matching element exists, so you might need an extra check just to be safe.
I basically 'recreated' underscore.js's findWhere method which is to die for.
The function:
function findWhere($array, $matching) {
foreach ($array as $item) {
$is_match = true;
foreach ($matching as $key => $value) {
if (is_object($item)) {
if (! isset($item->$key)) {
$is_match = false;
break;
}
} else {
if (! isset($item[$key])) {
$is_match = false;
break;
}
}
if (is_object($item)) {
if ($item->$key != $value) {
$is_match = false;
break;
}
} else {
if ($item[$key] != $value) {
$is_match = false;
break;
}
}
}
if ($is_match) {
return $item;
}
}
return false;
}
Example:
$cars = array(
array('id' => 1, 'name' => 'Toyota'),
array('id' => 2, 'name' => 'Ford')
);
$car = findWhere($cars, array('id' => 1));
or
$car = findWhere($cars, array(
'id' => 1,
'name' => 'Toyota'
));
I'm sure this method could easily reduce LOC. I'm a bit tired. :P
actually all array functions are designed for single dimension array.You always need to keep in mind that you are applying it on single dimension array.
function find_car_with_position($cars, $position) {
for($i=0;$i<count($cars);$i++){
if(array_search($search_val, $cars[$i]) === false){
// if value not found in array.....
}
else{
// if value is found in array....
}
}
}

cleaner way to pull dynamic nested elements in multidimensional array for sorting

Is there a cleaner way to extract a nested value from a 3 level deep multidimensional array, where i want to pull the result stacked inside the 3rd level, hwoever, i want to keep this dynamic so i can also grab elem from 2nd or 4th level by using an array as a parameter to determine this.
what im trying to do in the end is SORT using this element, but i cant find a way to conveniently indicate the element chain except for this way which i had to create myself:
public function keyBySubElement($nestedArray, array $subElemStack){
//essentially the loop below is doing this, but it is dynamic now so a user can specify different nested levels in the $subElemStack param.
//$nestedValue = $nestedArray[$subElemStack[0]][$subElemStack[1]];
foreach($subElemStack as $nestedElement){
if(isset($nestedValue) && is_array($nestedValue))
{
$nestedValue = $nestedValue[$nestedElement];
}
else
{
$nestedValue = $nestedArray[$nestedElement];
}
}
return $nestedValue;
}
e.g. to use this method:
assume the following data
$searchResults = array(
0 => array(
'title' => 'one',
array(
'ratings' => array(
'count' => '1'
)
)
),
1 => array(
'title' => 'two',
array(
'ratings' => array(
'count' => '5'
)
)
),
2 => array(
'title' => 'three',
array(
'ratings' => array(
'count' => '2'
)
)
),
);
foreach($searchResults as $k => $v){
$count = $this->keyBySubElement($v, array('ratings','count'));
$sortData[$k] = $count;
}
this gives me something like this
array(4) {
[0]=>
int(1)
[1]=>
int(5)
[2]=>
int(2)
}
now that i have access to my sub-sub elements value, tied in with its top level parent key, i can use it to sort the top level array by key using my new array $sortData as the reference key which can be reordered by the sub elements value that i want to sort with. i was next going just re-sort the original array by the new key values or something.
i saw a couple potential good examples, but i wasn't able to make them work. those examples are as follows:
[PHP sort: user function][1]
e.g. 1)
http://php.net/manual/en/function.sort.php#99419
e.g. 2)
Sort php multidimensional array by sub-value
e.g. 3)
/**
* Sort a 2 dimensional array based on 1 or more indexes.
*
* msort() can be used to sort a rowset like array on one or more
* 'headers' (keys in the 2th array).
*
* #param array $array The array to sort.
* #param string|array $key The index(es) to sort the array on.
* #param int $sort_flags The optional parameter to modify the sorting
* behavior. This parameter does not work when
* supplying an array in the $key parameter.
*
* #return array The sorted array.
*/
public function msort($array, $key, $sort_flags = SORT_REGULAR) {
if (is_array($array) && count($array) > 0) {
if (!empty($key)) {
$mapping = array();
foreach ($array as $k => $v) {
$sort_key = '';
if (!is_array($key)) {
$sort_key = $v[$key];
} else {
// #TODO This should be fixed, now it will be sorted as string
foreach ($key as $key_key) {
$sort_key .= $v[$key_key];
}
$sort_flags = SORT_STRING;
}
$mapping[$k] = $sort_key;
}
asort($mapping, $sort_flags);
$sorted = array();
foreach ($mapping as $k => $v) {
$sorted[] = $array[$k];
}
return $sorted;
}
}
return $array;
}
e.g. 4)
/**
* #param $array
* #param $cols
* #return array
*/
public function array_msort($array, $cols)
{
$colarr = array();
foreach ($cols as $col
=> $order) {
$colarr[$col] = array();
foreach ($array as $k => $row) {
$colarr[$col]['_'.$k] = strtolower($row[$col]);
}
}
$eval = 'array_multisort(';
foreach ($cols as $col => $order) {
$eval .= '$colarr[\''.$col.'\'],'.$order.',';
}
$eval = substr($eval,0,-1).');';
eval($eval);
$ret = array();
foreach ($colarr as $col => $arr) {
foreach ($arr as $k => $v) {
$k = substr($k,1);
if (!isset($ret[$k])) $ret[$k] = $array[$k];
$ret[$k][$col] = $array[$k][$col];
}
}
return $ret;
}
Since the data structure that they return is rather ugly and not condusive to sorting, my first move would be to reformat it into something that can be easily sorted. For example:
# create a new key, 'ratings', and put the contents of [0][ratings][count] in it
foreach ($searchResults as &$s) {
print_r($s);
# you could use your keybysubelement function to retrieve the value here
# rather than hardcoding it
$s['ratings'] = $s[0]['ratings']['count'];
unset($s[0]);
}
print_r($searchResults);
resulting data structure:
Array
(
[0] => Array
(
[title] => one
[ratings] => 1
)
[1] => Array
(
[title] => two
[ratings] => 5
)
[2] => Array
(
[title] => three
[ratings] => 2
)
)
It's then easy to create a sort function that will operate on this array to sort it according to the value in 'ratings':
# create a closure that will sort by a given key and in a given direction
# by default the order is ascending
function by_key($key, $dir = 'asc') {
return function ($a, $b) use ($key, $dir) {
if ($a[$key] > $b[$key]) {
if ($dir === 'asc')
return 1;
return -1;
}
elseif ($a[$key] < $b[$key]) {
if ($dir === 'asc')
return -1;
return 1;
}
return 0;
};
}
# sort by ratings, descending, using uasort and the custom search function:
uasort( $searchResults, by_key('ratings','desc') );
# print the results
foreach ($searchResults as $i) {
echo $i['title'] . ', ' . $i['ratings'] . PHP_EOL;
}
array order after sort:
two, 5
three, 2
one, 1
Sort by title:
uasort( $searchResults, by_key('title') );
Output:
one, 1
three, 2
two, 5

Php Array key=> value searching

HI I am fairly new to php.
I have an array
$arr = array(0 => array('GID'=>1,'groupname'=>"cat1",'members'=>array(0=>array('mid'=>11,'mname'=>'wwww'),1=>array('mid'=>12,'mname'=>'wswww'))),
1 => array('GID'=>2,'groupname'=>"cat2",'members'=>array(0=>array('mid'=>13,'mname'=>'gggwwww'),1=>array('mid'=>14,'mname'=>'wvvwww'))),
2 => array('GID'=>3,'groupname'=>"cat1",'members'=>array(0=>array('mid'=>15,'mname'=>'wwddsww')),1=>array('mid'=>16,'mname'=>'wwwdddw')));
ie...,I have GID,groupname,mid(member id),mname(member name).I want to insert a new mid and mname into a group if it is already in the array ,if it is not exists then create a new subarray with these elements..I also need to check a member id(mid) is also present.........................I used the code but its not working fine............. if (!empty($evntGroup)) {
foreach ($evntGroup as $k => $group) {
if ($group['GID'] == $group_id) {
foreach($group as $j=> $mem){
if($mem['mid'] == $mem_id){
unset($evntGroup[$k]['members'][$j]['mid']);
unset($evntGroup[$k]['members'][$j]['mname']);
}
else{
$evntGroup[$k]['members'][] = array(
'mid' => $mem_id,
'mname' => $mem_name);
}}
} else {
$evntGroup[] = array(
'GID' => $group_id,
'groupname' => $Group['event_group_name'],
'members' => array(
0 => array(
'mid' => $mem_id,
'mname' => $mem_name
)
)
);
}
}
} else {
$evntGroup[$i]['GID'] = $group_id;
$evntGroup[$i]['groupname'] = $Group['event_group_name'];
$evntGroup[$i]['members'][] = array(
'mid' => $mem_id,
'mname' => $mem_name);
$i++;
}
In the form of a function, the easiest solution will look something like this:
function isGidInArray($arr, $val) {
foreach($arr as $cur) {
if($cur['GID'] == $val)
return true;
}
return false;
}
You've updated your question to specify what you want to do if the specified GID is found, but that's just a trivial addition to the loop:
function doSomethingIfGidInArray($arr, $val) {
foreach($arr as $cur) {
if($cur['GID'] == $val) {
doSomething();
break; //Assuming you only expect one instance of the passed value - stop searching after it's found
}
}
}
There is unfortunately no native PHP array function that will retrieve the same index of every array within a parent array. I've often wanted such a thing.
Something like this will match if GID equals 3:
foreach( $arr as $item ) {
if( $item['GID'] == 3 ) {
// matches
}
}
There is the code
function updateByGid(&$array,$gid,$groupname,$mid,$mname) {
//For each element of the array
foreach ($array as $ii => $elem) {
//If GID has the same value
if ($elem['GID'] == $gid) {
//Insert new member
$array[$ii]['members'][]=array(
'mid'=>$mid,
'mname'=>$mname);
//Found!
return 0;
}
}
//If not found, create new
$array[]=array(
'GID'=>$gid,
'groupname'=>$groupname,
'members'=>array(
0=>array(
'mid'=>$mid,
'mname'=>$mname
)
)
);
return 0;
}

Categories