2017-12-08 40 views
6

のすべてのパス:私は私がしているすべての異なるパスを見ることができるように再帰的にそれを通って移動する方法を把握しようとしている再帰的サイクルの私は、次の(JSON)オブジェクト持って配列

$obj = json_decode('{ 
    "Group1": { 
     "Blue": { 
      "Round": [ 
       "Harold", 
       "Arthur", 
       "Tom" 
      ] 
     }, 
     "Green": { 
      "Round": [ 
       "Harold" 
      ], 
      "Circle": [ 
       "Todd", 
       "Mike" 
      ] 
     } 
    }, 
    "Group2": { 
     "Blue": { 
      "Round": [ 
       "Peter" 
      ] 
     } 
    } 
}', true); 

を配列。

4つの別々のエコーまたは4行の文字列にすることができます。 >は、何かで置き換えられても何も全く置き換えられない可能性があります。もし各ラインが別々にエコーされたり、配列にプッシュされていれば、おそらく最も柔軟性があります。

Group1 - Blue - Round - (Harold, Arthur, Tom) 
Group1 - Green - Round - (Harold) 
Group1 - Green - Circle - (Todd, Mike) 
Group2 - Blue - Round - (Peter) 

私の周りに私の頭を包むことはできませんので、どんな助けにも感謝します。

私は各等を介して何とかサイクルをできると思っています:

foreach($obj as $index => $value) 
{ 
    // and then somehow do this until you reach an array? 
} 
+0

あなたは各メンバーを通過する必要がありますか?多分 'array_walk' – Erwin

+0

Yeaのようなものがほしいと思うかもしれません。うーん、深い配列でどう動くかわからないけど、それを試してみるよ – bryan

+0

あなたのオブジェクトは常に 'Group> Color> Shapes> Names'の形式ですか?あるいは、追加のカテゴリや何かが存在する可能性がありますか? – Erwin

答えて

6

。しかし、これはアレイレベルが増加する場合には有効です。あなたの例function.For https://eval.in/915070

+0

これは素晴らしい作品です!私はそれを理解したいと思いますが、コメントに感謝し、時間を割いてください。これを試して解剖して学びましょう!私は本当に助けに感謝します – bryan

0

uはチューン

$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"; 

} 

続いことができ、この

私が作成したサンプル再帰プログラムを試してみてはサンプル出力です。

Group1 =>Blue =>Round =>Harold Arthur Tom 
Green =>Round =>Harold Circle =>Todd Mike 
Group2 =>Blue =>Round =>Peter 
+0

期待した結果をお届けしてください。 – mickmackusa

+0

@mickmackusaあなたのことを熱心に待っています; p、この答えは配列だけのオブジェクトを扱いませんが、近いです。 –

+0

(私はそれに取り組んでいます - 私の娘と私の注意を分けている間)@lawrence – mickmackusa

2

これは、配列の深度が異なる場合に有効です。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"; 

注:のみ与えられたサンプルでテスト

traverse array from outer to inner
traverse array from inner to outer

+2

前提に基づいて、これはより正確です。+ 1 –

+0

@mickmackusa、あなたのコメントへの即時の返答に申し訳ありません。私は私の答えに驚いた。あなたは今それをチェックできますか?もしそうなら、ダウンボートを削除してください。ありがとうございました。 –

+0

私の答えに誰かが泣き言を言うと、私は最初、不十分な私の元長の答えに謝罪します。しかし、今私はそれをimporved、あなたはdownvoteを離すことができます、それは今働くためです。 –

2

私が作成した単純な再帰 - :私は主に

// 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>'; 
} 

出力RecursiveIteratorIteratorクラスの機能を使用しています。以前のキー値を1つの変数に格納し、前のキーに従ってすべてのデータを追加し、新しい配列を作成します(前のすべてのキーをインデックスとして、最後の要素を値として含みます)。私は非常にシンプルで読みやすいものに私の方法を煮詰めてきた

$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

これも良い答えです。証拠:http://sandbox.onlinephpfunctions.com/code/511d8ce024902420a70a3af6cc6621bdc37f796e説明を少しして、私は+1してうれしいです。 – mickmackusa

+0

説明が追加されました@mickmackusa –

0

:次のコードを試してみてください。説明については、インラインコメントを参照してください。私は2つのバージョンを持っています:4行エコー関数と配列関数を返す。

*ので、この方法は非常に特にこの問題のために構築されることに注意してください:入力配列は、常に少なくとも二つのレベルと

方法#1の深さを持っています

  • - 文字列のエコー関数内から:(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); 
    

    出力:

    Group1 > Blue > Round > One > (Lawrence, Anant, B.) 
    Group1 > Blue > Round > Two > (Erwin) 
    Group1 > Green > (Bryan, Mick) 
    Group2 > (Peter, Kris) 
    

    方法#2 - パスの4要素の配列を返す: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)); 
    

    出力:

    array (
        0 => 'Group1 > Blue > Round > One > (Lawrence, Anant, B.)', 
        1 => 'Group1 > Blue > Round > Two > (Erwin)', 
        2 => 'Group1 > Green > (Bryan, Mick)', 
        3 => 'Group2 > (Peter, Kris)', 
    ) 
    

    そして1つの最終アップデート:

    私が与えることができる最高のアドバイスは、この中間のステップを切り出し、ちょうど(再帰なし/必須積み重ねない)新しい所望の出力にyour raw/initial json stringを変換するために、次のようになります。

    コード:(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

@ブライアン私の一日遅い答えを見ましたか?私はそれが群衆で失われたのではないかと心配しますが、他の人よりも理解するのがはるかに簡単です(特に受け入れられた回答IMOと比較して)。 – mickmackusa

0
ここ

は発電機能を備えた私の感想です:

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); 
} 

onlineそれを試してみてください。

+0

申し訳ありません@Joe明らかに遅く/洗練された答えはこのページで認められません。私の答えはちょうど24時間遅れ、私が他のすべての正解に対処したアップフォーメントにもかかわらず、往復はなかった。 StackOverflowは常に正義の場ではありません。 – mickmackusa