Самый элегантный способ ходить по деревьям в PHP - PullRequest
1 голос
/ 23 июня 2010

У меня есть такие деревья:

$tree = array("A", array(
            array("B", 1),
            array("C", 2),
            array("D",
                array("E",
                    array("F")),
                array("G")),
            array("H", 3)));

Каждый узел является массивом, тип узла является его первым элементом, а другие элементы являются аргументами узла (они могут быть списком других узлов, одним узлом, некоторым значением и т. Д .; узел не может иметь аргумента, одного аргумента или нескольких аргументов ).

Как вы думаете, какой самый элегантный способ ходить по деревьям такого типа?

Я предложил две возможности:

1) используя switch оператор

/*
 * + shorter
 * + fall-througs (easy way to handle more nodes with same code)
 *
 * - worse readability
 */
function my_tree_walker($tree)
{
    switch ($tree[0]) {
        case 'A':
            list($_, $subnodes) = $tree;
            $ret = '';

            foreach ($subnodes as $subnode) {
                $ret .= my_tree_walker($subnode);
            }

            return $ret;

        break;
        case 'B': /*...*/ break;
        case 'C': /*...*/ break;
        case 'D': /*...*/ break;
        case 'E': /*...*/ break;
        case 'F': /*...*/ break;
        case 'G': /*...*/ break;
        case 'H': /*...*/ break;
    }
}

2) объект с методом для каждого типа узла

/*
 * + better readability
 * + more declarative
 *
 * - longer
 * - `new static` is PHP >=5.3 only
 */

abstract class TreeWalker
{
    protected function __construct(){}

    final protected function walk($node)
    {
        $nodetype = array_shift($node);
        return call_user_func_array(array($this, 'walk' . $nodetype), $node);
    }

    public static function w($tree)
    {
        $instance = new static;
        return $instance->walk($tree);
    }
}

final class MyTreeWalker extends TreeWalker
{
    protected function __construct()
    {
        // initialize
    }

    private function walkA($subnodes)
    {
        $ret = '';

        foreach ($subnodes as $subnode) {
            $ret .= $this->walk($subnode);
        }

        return $ret;
    }

    private function walkB($n) { /*...*/ }
    private function walkC($n) { /*...*/ }
    private function walkD($subnode) { /*...*/ }
    private function walkE() { /*...*/ }
    private function walkF() { /*...*/ }
    private function walkG() { /*...*/ }
    private function walkH($n) { /*...*/ }
}

Или вы предлагаете еще более элегантный способ прогулок по деревьям?

Я также рассматривал узлы как объекты, и вместо отдельных обходчиков деревьев каждый узел имел бы методы для прогулок внутри. Однако я думаю, что это усложнит обслуживание кода, потому что части кода ходящих будут размещаться в разных местах, и будет сложнее использовать один и тот же код для большего количества узлов.

Ответы [ 5 ]

3 голосов
/ 23 июня 2010

Я думаю, что простота элегантна.

Не нужно изобретать велосипед! PHP оснащен SPL (стандартная библиотека PHP) , которая предлагает несколько итераторов , которые могут сделать всю работу за вас.

Несколько, чтобы проверить было бы RecursiveIteratorIterator и RecursiveArrayIterator

3 голосов
/ 23 июня 2010
0 голосов
/ 23 марта 2019

Я сделал простую рекурсивную функцию, которая эффективно ходит по дереву. Вот оно

   function deep_cetegories($categories){
     foreach($categories as $category)
  {
    print_r((json_encode($category['category_name'])));
    if(isset($category['children']))
    {
        deep_cetegories($category['children']);
    }

  }
}
0 голосов
/ 13 апреля 2017

Я рекомендую эту библиотеку: https://packagist.org/packages/lukascivil/treewalker

TreeWalker - это простая и небольшая библиотека, которая поможет вам быстрее работать с манипуляциями со структурами в PHP

  • getdiff () -Получить разницу в json
  • walker () - Редактировать json (Рекурсивно)
  • structMerge () - Объединить две структуры
  • createDynamicallyObjects () - Создать вложенную структуру с помощью динамических ключей
  • getDynamicallyValue () - Динамическое получение свойства структуры
  • setDynamicallyValue () - Динамический доступ к свойству структуры для установки значения
0 голосов
/ 01 июля 2010

Я объединил оба пути и создал DSL:

A ($subnodes) {
    $ret = '';
    foreach ($subnodes as $subnode) {
        $ret .= WALK($subnode);
    }

    return $ret;
}
B ($n) { /*...*/ }
C ($n) { /*...*/ }
D ($subnode) { /*...*/ }
E () { /*...*/ }
F () { /*...*/ }
G () { /*...*/ }
H ($n) { /*...*/ }

, который переведен на PHP.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...