0

エンティティとその子を含む多次元配列から順序なしリストを作成する際に問題があります。問題は、ツリーが非常に深くなり、再帰によってサーバーに不要な負荷が発生する可能性があるため、再帰を使用したくないことです。

これはそのような配列の例です ( titleandを含むように簡略化されてchildrenおり、エンティティはオブジェクトにすることもできます)。

$array = array(
    array('title' => '1', 'children' => array()),
    array('title' => '2', 'children' => array()),
    array('title' => '3', 'children' => array()),
    array('title' => '4', 'children' => array(
        array('title' => '41', 'children' => array()),
        array('title' => '42', 'children' => array()),
        array('title' => '43', 'children' => array()),
        array('title' => '44', 'children' => array(
            array('title' => '441', 'children' => array()),
            array('title' => '442', 'children' => array()),
            array('title' => '443', 'children' => array()),
            array('title' => '444', 'children' => array(
                array('title' => '4441', 'children' => array()),
                array('title' => '4442', 'children' => array()),
                array('title' => '4443', 'children' => array())
            )),
        )),
        array('title' => '45', 'children' => array())
    )),
    array('title' => '5', 'children' => array()),
    array('title' => '6', 'children' => array(
        array('title' => '61', 'children' => array()),
        array('title' => '62', 'children' => array()),
        array('title' => '63', 'children' => array())
    )),
    array('title' => '7', 'children' => array())
);

ここでSOについていくつかの調査を行って、私が望むものに非常に近いこのソリューションを思いつきました:

<html>
<head></head>
<body>
<ul>
<?php
$stack = $array;
$i = 0;
$counts = array();
while(!empty($stack)) {
    $node = array_shift($stack);
    echo "<li>{$node['title']}";
    if($node['children']) {
        echo "<ul>";
        $counts[] = count($node['children']);
        $node['children'] = array_reverse($node['children']);
        foreach($node['children'] as $ch)
            array_unshift($stack, $ch);
    }
    if(!empty($counts)) {
        end($counts);
        if($counts[$key] == 0) {
            echo "</ul>";
            array_pop($counts);
        } else {
            $counts[$key]--;
        }
    }
    if(!$node['children']) {
        echo "</li>";
    }

    // just to make sure we won't end in infinite loop
    $i++;
    if($i == 50) break;
}
?>
</ul>
</body>
</html>

出力は以下のとおりです。ご覧のとおり、問題は</ul>サブツリーを閉じることだけです。私の質問: 私はそれを考えすぎているのでしょうか、それとも盲目で明らかな間違いに気付かないのでしょうか? 有限の解決策に私を押し進めてくれますか、それともあなた自身のものを与えてくれますか?

出力:

  • 1
  • 2
  • 3
  • 4
    • 41
    • 42
    • 43
    • 44
      • 441
      • 442
      • 443
      • 444
        • 4441
        • 4442
        • 4443
      • 45
    • 5
    • 6
      • 61
      • 62
      • 63
  • 7
4

2 に答える 2

1

これはコードの修正ではありませんが、とにかく役立つかもしれません:

function helper($input) {
  $input[] = '</ul>';
  $input = array_reverse($input);
  $input[] = '<ul>';

  // output
  while (sizeof($input) > 0) {
    $el = array_pop($input);

    if (!is_array($el)) {
      echo $el; 
    }
    else {
      // add current element
      $input[] = sprintf('<li>%s', $el['title']);

      // add children
      if (sizeof($el['children']) > 0) {
        $input[] = '</ul>';
        $input = array_merge($input, array_reverse($el['children']));
        $input[] = '<ul>';
      }

      // add closing li
      $input[] = '</li>';
    }
  }
}

helper($array);

デモ: http://codepad.viper-7.com/qin15V

于 2013-01-14T16:48:10.210 に答える
0

OK、いつものask for a solution You are solving for hours and immediately You are out with one...ように--少しリラックスした後、もう少し考えて、この解決策を思いつきました:

<html>
<head></head>
<body>
<ul>
<?php
$i = 0;
$counts = array();
while(!empty($stack)) {
    $node = array_shift($stack);
    if(!empty($counts)) {
        while(end($counts) === 0) {
            $key = key($counts);
            echo "</li></ul>";
            array_pop($counts);
        }
        end($counts);
        $key = key($counts);
        if(isset($counts[$key])) {
            $counts[$key]--;
        }
    }
    echo "<li>{$node['title']}";
    if($node['children']) {
        echo "<ul>";
        $counts[] = count($node['children']);
        $node['children'] = array_reverse($node['children']);
        foreach($node['children'] as $ch)
            array_unshift($stack, $ch);
    }
    if(!$node['children']) {
        echo "</li>";
    }


    $i++;
    if($i == 50) break;
}
?>
</ul>
<p>$i = <?php echo $i; ?></p>
</body>
</html>

問題は、ツリーをずっと上に戻って値whileを減算する必要がある別のものを欠いていたことでした...$counts

誰かが私のあまりきちんとした解決策ではなく、受け入れられるべきより良い解決策を投稿する場合に備えて、私は自分の答えを受け入れて待ちます。

于 2013-01-14T16:30:34.083 に答える