I have the following(json) object:
$obj = json_decode(\'{
\"Group1\": {
\"Blue\": {
\"Round\": [
\"Harold\",
Try this
i have created sample recursive program which u can tune
$obj = json_decode('{"Group1": {
"Blue": {
"Round": [
"Harold",
"Arthur",
"Tom"
]
},
"Green": {
"Round": [
"Harold"
],
"Circle": [
"Todd",
"Mike"
]
}
},
"Group2": {
"Blue": {
"Round": [
"Peter"
]
}
}
}');
recursive($obj);
function recursive($obj){
if(is_array($obj)){
foreach ($obj as $k => $v) {
echo $v." ";
}
return;
}
foreach ($obj as $key => $value) {
echo $key. " =>";
recursive($value);
}
echo "\n";
}
Following is sample output
Group1 =>Blue =>Round =>Harold Arthur Tom
Green =>Round =>Harold Circle =>Todd Mike
Group2 =>Blue =>Round =>Peter
I have created simple recursive function.For your example. Store previous key values in one variable and add all data according to previous key and create new array.(which contain all previous keys as index and last element as value) . Try following code:
$obj = json_decode('{
"Group1": {
"Blue": {
"Round": [
"Harold",
"Arthur",
"Tom"
]
},
"Green": {
"Round": [
"Harold"
],
"Circle": [
"Todd",
"Mike"
]
}
},
"Group2": {
"Blue": {
"Round": [
"Peter"
]
}
}
}', true);
function traverse_array($array,$key="",$prev="",&$final_op=array())
{
if(is_array($array))
{
$prev .= $key." - ";
foreach ($array as $key => $value) {
traverse_array($value,$key,$prev,$final_op);
}
}
else
{
$prev =trim($prev," - ");
$final_op[$prev][]=$array;
}
return $final_op;
}
$data = traverse_array($obj);
foreach ($data as $key => $value) {
echo $key." (".implode(",", $value).")";
echo PHP_EOL;
}
DEMO
Tested only on the given sample. But this should work if array levels are increased. I mainly use RecursiveIteratorIterator
class functions
// Initialize RecursiveIteratorIterator
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($obj), RecursiveIteratorIterator::SELF_FIRST);
$paths = array(); // Paths storage
foreach ($iterator as $k => $v) { // Loop thru each iterator
if (!$iterator->hasChildren()) { // Check if iterator hasChildren is false
$innermost = $iterator->getSubIterator($iterator->getDepth()); // Get innermost child which is the array
for ($p = array(), $i = 0, $z = $iterator->getDepth(); $i <= $z; $i++) { // Loop and push each path to the innermost array
$p[] = $iterator->getSubIterator($i)->key();
}
array_pop($p); // Remove key
$innermost = (array)$innermost; // Cast innermost to array
$p[] = '(' . implode(', ', $innermost) . ')'; // push formatted innermost array to path
$path = implode(' - ', $p); // implode the path
$paths[] = $path; // store to list of paths array
}
}
$paths = array_unique($paths); // remove exactly same paths
foreach ($paths as $value) { // Loop and echo each path
echo $value.'<br>';
}
Output:- https://eval.in/915070
I've boiled down my method to something VERY simple and easy to read. See inline comments for explanations. I have two versions: a 4-line echoing function and an array returning function.
*Note this method is very SPECIFICALLY built for this question because:
Method #1 - echo strings from inside the function: (Demo)
$array=json_decode('{
"Group1": {
"Blue": {
"Round": {
"One": [
"Lawrence",
"Anant",
"B."
],
"Two": [
"Erwin"
]
}
},
"Green": [
"Bryan",
"Mick"
]
},
"Group2": [
"Peter",
"Kris"
]
}', true);
function recurse($array,$path=''){
foreach($array as $k=>$v){
if(!is_array(current($v))){ // check type of the first sub-element's value
echo ($path?"$path > ":''),"$k > (".implode(', ',$v).")\n"; // don't recurse, just implode the indexed elements
}else{ // recurse because at least 2 levels below
recurse($v,($path?"$path > $k":$k)); // build path appropriately
}
}
}
recurse($array);
Output:
Group1 > Blue > Round > One > (Lawrence, Anant, B.)
Group1 > Blue > Round > Two > (Erwin)
Group1 > Green > (Bryan, Mick)
Group2 > (Peter, Kris)
Method #2 - return a 4-element array of paths: (Demo)
function recurse($array,$path='',&$result=[]){
foreach($array as $k=>$v){
if(!is_array(current($v))){ // check type of the first sub-element's value
$result[]=($path?"$path > ":'')."$k > (".implode(', ',$v).')'; // don't recurse, just implode the indexed elements
}else{ // recurse because at least 2 levels below
recurse($v,($path?"$path > ":'').$k,$result); // build path appropriately
}
}
return $result;
}
var_export(recurse($array));
Output:
array (
0 => 'Group1 > Blue > Round > One > (Lawrence, Anant, B.)',
1 => 'Group1 > Blue > Round > Two > (Erwin)',
2 => 'Group1 > Green > (Bryan, Mick)',
3 => 'Group2 > (Peter, Kris)',
)
And one final update:
The best advice I can give would be to cut out this middle step and just convert your raw/initial json string to your new desired output (no recursion/stacking required):
Code: (Demo)
$seperateArray = json_decode('[
{ "tier1": "Group1", "tier2": "Blue", "tier3": "Round", "tier4": "One", "tier5": "Lawrence" },
{ "tier1": "Group1", "tier2": "Blue", "tier3": "Round", "tier4": "One", "tier5": "Anant" },
{ "tier1": "Group1", "tier2": "Blue", "tier3": "Round", "tier4": "One", "tier5": "B." },
{ "tier1": "Group1", "tier2": "Blue", "tier3": "Round", "tier4": "Two", "tier5": "Erwin" },
{ "tier1": "Group1", "tier2": "Green", "tier3": "Bryan" },
{ "tier1": "Group1", "tier2": "Green", "tier3": "Mick" },
{ "tier1": "Group2", "tier2": "Peter" },
{ "tier1": "Group2", "tier2": "Kris" }]',true);
foreach($seperateArray as $row){
$last_val=current(array_splice($row,-1)); // extract last element, store as string
$results[implode(' > ',$row)][]=$last_val;
}
foreach($results as $k=>$v){
echo "$k > (",implode(', ',$v),")\n";
}
// same output as earlier methods
This works for different depth of the array, check the live demo.
while(count($array) != count($array, 1)) // stop when $array is one dimension
{
$temp = [];
foreach($array as $k => $v)
{
if(is_array($v))
{
if(count($v) != count($v, 1)) // check if reached the inner most array
{
foreach($v as $kk => $vv)
{
$temp[$k . ' - ' . $kk] = $vv;
}
}
else
$temp[$k] = '(' . implode($v, ', ') . ')';
}else
$temp[$k] = $v;
}
$array = $temp;
}
foreach($array as $k => $v)
echo $k . ' - ' . $v . "\n";
Note:
traverse array from outer to inner
traverse array from inner to outer
Here's my take with a generator function:
function paths(array $a)
{
// if first item is an array, recurse
if (is_array(reset($a))) {
foreach ($a as $k => $v) {
foreach (paths($v) as $path) {
// yield "key - subpath"
yield sprintf('%s - %s', $k, $path);
}
}
} else {
// yield leaf
yield sprintf('(%s)', implode(', ', $a));
}
}
foreach (paths($obj) as $path) {
printf("%s\n", $path);
}
Try it online.