Построение неупорядоченного списка из таблицы MYSQL из 5 столбцов в PHP (деревья и рекурсия) - PullRequest
0 голосов
/ 18 ноября 2010

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

Это таблица MYSQL:


Родитель / Ребенок / Внук / Гранд-внучат / Гранд-Гранд-внучат

Франция / Аквитания / Dordogne / Бержерак / Айзек

Франция / Аквитания / Dordogne / Nontron / Nontron

Кипр / Пафос / Район Пафоса / Корал Бэй / Корал Бэй

Дания / Южная Дания / Лангеланн / Рудкобинг / Лангеланн

Египет / Синайский полуостров / Красное море / Шарм Эль Шейх / Шарм Эль Шейх


Неупорядоченный список должен выглядеть так:

  • Франция
    • Аквитания
      • Дордонь
        • Бержерак
          • Isaac
        • Nontron
          • Nontron
  • Кипр
    • Пафос
      • Пафосский округ
        • Коралловый залив
          • Коралловый залив

и т.д ...

По сути, создание меню неупорядоченного списка, представляющего все пять уровней, с правильной группировкой.

Я играл со следующей функцией, чтобы попытаться получить то, что я хочу: http://kevin.vanzonneveld.net/techblog/article/convert_anything_to_tree_structures_in_php/

Может ли кто-нибудь предоставить дополнительную информацию о том, как решить эту проблему? Я попытался построить циклы для каждого уровня, но быстро обнаружил, что это бесполезно, и что следует использовать рекурсивные функции.

Ответы [ 2 ]

0 голосов
/ 18 ноября 2010

Хорошо, мне удалось собрать воедино фрагмент кода, который, кажется, работает.

Сначала я вручную объединяю столбцы в строки / column1 / column2 / column3 / column4 / column5 в одномерном массиве;Затем, применяя функции из данного URL, рассмотрим этот простой массив в дерево массивов.Наконец, я использую функцию makeULLI для генерации неупорядоченного списка со ссылками для каждого присутствующего узла.Я расширил код, добавив пользовательские пути к URL-адресам в зависимости от глубины ссылки, для использования в SEO-дружественных ссылках, но я лишился этого.

Я прилагаю код, который делает все это и удивительномаленький.Код должен работать на любом количестве уровней, я запустил его в таблице, содержащей около 400 строк (5 столбцов), и он выполняется за 0,0168 секунды.Если кто-нибудь увидит дальнейшую оптимизацию кода, я был бы благодарен.

    foreach ($geoArray as $result)
    {
    $mynewGEO[] = $result['parent'];
    $mynewGEO[] = $result['parent'].'/'.$result['child'];       
    $mynewGEO[] = $result['parent'].'/'.$result['child'].'/'.$result['grandchild'];     
    $mynewGEO[] = $result['parent'].'/'.$result['child'].'/'.$result['grandchild'].'/'.$result['grand-grandchild'];     
    $mynewGEO[] = $result['parent'].'/'.$result['child'].'/'.$result['grandchild'].'/'.$result['grand-grandchild'].'/'.$result['grand-grand-grandchild'];
    }

$key_files = array_combine(array_values($mynewGEO), array_values($mynewGEO));
$tree = explodeTree($key_files, "/", true);
echo makeULLI($tree);

function makeULLI($array) {
    $return = "<ul>\n";

    if (is_array($array) && count($array) > 0) {
        foreach ($array as $k => $v) {
            if($k == "__base_val") continue;
            // determine the __base_val value in orde to use for the link.
            $our_linky = ( is_array($v) ? $v["__base_val"] : $v );

            if (is_array($v) && count($v) > 0) {
                $return .= "\t<li><a href=\"".$our_linky."/\" >" . $k ."</a>". makeULLI($v) . "</li>\n";
            }
            else {
                $return .= "\t<li><a href=\"".$our_linky."/\" >" . $k . "</a></li>\n";
                //to return full path
                //$return .= "\t<li><a href=\" # \" >" . $v . "</a></li>\n";
            }
        }
    } else {}

    $return .= "</ul>";

    return $return;
}

function explodeTree($array, $delimiter = '_', $baseval = false)
{
  if(!is_array($array)) return false;
  $splitRE   = '/' . preg_quote($delimiter, '/') . '/';
  $returnArr = array();
  foreach ($array as $key => $val) {
    // Get parent parts and the current leaf
    $parts  = preg_split($splitRE, $key, -1, PREG_SPLIT_NO_EMPTY);
    $leafPart = array_pop($parts);

    // Build parent structure
    // Might be slow for really deep and large structures
    $parentArr = &$returnArr;
    foreach ($parts as $part) {
      if (!isset($parentArr[$part])) {
        $parentArr[$part] = array();
      } elseif (!is_array($parentArr[$part])) {
        if ($baseval) {
          $parentArr[$part] = array('__base_val' => $parentArr[$part]);
        } else {
          $parentArr[$part] = array();
        }
      }
      $parentArr = &$parentArr[$part];
    }

    // Add the final part to the structure
    if (empty($parentArr[$leafPart])) {
      $parentArr[$leafPart] = $val;
    } elseif ($baseval && is_array($parentArr[$leafPart])) {
      $parentArr[$leafPart]['__base_val'] = $val;
    }
  }
  return $returnArr;
}
0 голосов
/ 18 ноября 2010

На самом деле, здесь нет необходимости в рекурсии. Дерево может быть построено путем многократного использования функции вставки, и эта функция может быть безопасно реализована в императивном стиле.

/** 
 * insert($tree,array('a','b','c'),$value) 
 *   ensures that $tree['a']['b']['c'] == $value
 */
function insert(&$tree,$path,$value)
{
  $modified = &$tree;
  foreach ($path as $segment) 
  {
    if (!isset($modified[$segment])) $modified[$segment] = array();
    $modified = & $modified[$segment];
  }
  $modified = $value;  
}

Как только вы это сделаете, вставка всех элементов в дерево будет довольно простой, если ваши строки будут в формате, подобном array('France','Aquitaine','Dordogne','Bergerac','Issac'):

foreach ($rows as $row)
  insert($tree, $row, array());

Возможной оптимизацией является сортировка строк лексикографически, что означает, что все строки с одинаковым префиксом будут обрабатываться вместе, и, таким образом, вы можете сэкономить время обхода.

...