Recursively cycle every path of an array

后端 未结 6 1761
[愿得一人]
[愿得一人] 2021-01-01 01:02

I have the following(json) object:

$obj = json_decode(\'{
    \"Group1\": {
        \"Blue\": {
            \"Round\": [
                \"Harold\",
                 


        
相关标签:
6条回答
  • 2021-01-01 01:05

    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 
    
    0 讨论(0)
  • 2021-01-01 01:06

    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

    0 讨论(0)
  • 2021-01-01 01:11

    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

    0 讨论(0)
  • 2021-01-01 01:13

    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:

    • The input array will ALWAYS have a depth of at least two levels AND

    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
    
    0 讨论(0)
  • 2021-01-01 01:24

    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

    0 讨论(0)
  • 2021-01-01 01:31

    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.

    0 讨论(0)
提交回复
热议问题