Здравствуйте! Есть массив Код (Text): $a = [ [0] => [ 'lft' => 1, 'rgt' => 6, 'depth' => 1, 'title' => 'cat1' ], [1] => [ 'lft' => 2, 'rgt' => 3, 'depth' => 2, 'title' => 'cat1-2' ], [2] => [ 'lft' => 4, 'rgt' => 5, 'depth' => 2, 'title' => 'cat1-3' ], ]; Хочу получить вложенные деревья в 'children', чтобы получилось так Код (Text): $a = [ [0] => [ 'lft' => 1, 'rgt' => 6, 'depth' => 1, 'title' => 'cat1', 'children' => [ [0] => [ 'lft' => 2, 'rgt' => 3, 'depth' => 2, 'title' => 'cat1-2' ], [1] => [ 'lft' => 4, 'rgt' => 5, 'depth' => 2, 'title' => 'cat1-3' ], ], ], ]; Запутался в рекурсии и в индексах lft, rgt... Не подскажите, как примерно надо это обыграть? Есть рабочий код, но нужно избавиться от each... Не могу осмыслить Код (Text): function nestedArray(&$result, $prefix = '', $level = -1) { $new = []; if (is_array($result)) { while(list($n, $sub) = each($result)) { $new[] = $sub; $count = count($new); $new[$count - 1]['_tree_level'] = $level + 1; if ($sub['rgt'] - $sub['lft'] != 1) { $new[$count - 1]['children'] = nestedArray($result, $prefix, $new[$count - 1]['_tree_level']); $new[$count - 1]['expanded'] = true; } $next_id = key(next($result)); if ($next_id && $result[$next_id]['depth'] != $sub['depth']) { return $new; } } } return $new; }
я немного поофтоплю.. пока еще смотрю Ваш код.. мне вот интересно что заставляет людей использовать ссылке.. вечно с ними какие то засады.. --- Добавлено --- list интересная кстати штука.. недавно читал)) Код (Text): Внимание В PHP 5 list() присваивает значения начиная с самого правого. В PHP 7 list() - с самого левого. --- Добавлено --- уровней может быть много? сколько может быть элементов первого уровня? где указаны в массивах их родительские категории? вижу глубину, но глубина это не родительская категория.. она показывает уровень, а не какому массиву принадлежит вложенный массив. .
Ссылка в данном случае нужна, т.к. во всей рекурсии прогулка идет по одному и тому же массиву со сменой указателя. Это Nested Sets, там родитель определяется по left-right Код не мой, но переделать для совместимости не могу... Тут с внутренними указателями в массиве организовано (each, next). foreach и while в рекурсии начинают перебирать массив сначала...
Да, ступил... $result - это массив из примера $a Верхний уровень только один и имеет left = 1 Вот пример дерева
Там всё гораздо проще, когда есть depth, можно даже без рекурсии. Простой стек организовываете, спускаясь по уровням добавляете ссылку на children, поднимаясь - выталкиваете обратно. Его для этого видимо туда и вставляют, так-то он для nested Sets не нужен. Я правда именно вашу задачу никогда не решал, я так обычно вывожу nested sets напрямую.
Спасибо! Подобрал такое решение Код (Text): $stack = array(); $arraySet = array(); foreach( $a as $intKey=>$arrValues) { $stackSize = count($stack); while($stackSize > 0 && $stack[$stackSize-1]['rgt'] < $arrValues['lft']) { array_pop($stack); $stackSize--; } $link =& $arraySet; for($i=0;$i<$stackSize;$i++) { $link =& $link[$stack[$i]['index']]["children"]; } $tmp = array_push($link, array ('item'=>$arrValues,'children'=>array())); array_push($stack, array('index' => $tmp-1, 'rgt' => $arrValues['rgt'])); } print_r($arraySet);
Начал изучать по этой статье http://www.getinfo.ru/article610.html . Не понимаю, как из этого потом вывести дерево? Код (Text): -- phpMyAdmin SQL Dump -- version 4.7.7 -- https://www.phpmyadmin.net/ -- -- Хост: 127.0.0.1:3306 -- Время создания: Янв 19 2019 г., 19:21 -- Версия сервера: 5.7.20 -- Версия PHP: 7.2.0 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET AUTOCOMMIT = 0; START TRANSACTION; SET time_zone = "+00:00"; /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8mb4 */; -- -- База данных: `nested_sets` -- -- -------------------------------------------------------- -- -- Структура таблицы `my_tree` -- CREATE TABLE `my_tree` ( `id` int(10) NOT NULL, `name` varchar(150) NOT NULL, `left_key` int(10) NOT NULL DEFAULT '0', `right_key` int(10) NOT NULL DEFAULT '0', `level` int(10) NOT NULL DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Дамп данных таблицы `my_tree` -- INSERT INTO `my_tree` (`id`, `name`, `left_key`, `right_key`, `level`) VALUES (1, '1', 1, 23, 1), (2, '2', 2, 9, 2), (3, '3', 10, 23, 2), (4, '4', 24, 31, 2); -- -- Индексы сохранённых таблиц -- -- -- Индексы таблицы `my_tree` -- ALTER TABLE `my_tree` ADD PRIMARY KEY (`id`), ADD KEY `left_key` (`left_key`,`right_key`,`level`); -- -- AUTO_INCREMENT для сохранённых таблиц -- -- -- AUTO_INCREMENT для таблицы `my_tree` -- ALTER TABLE `my_tree` MODIFY `id` int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5; COMMIT; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; Делаю запрос Код (Text): SELECT id, name, level FROM my_tree ORDER BY left_key Выводит список Код (Text): id name level 1 1 1 2 2 2 3 3 2 4 4 2
Вот так по интересней Код (Text): INSERT INTO `my_tree` (`id`, `name`, `left_key`, `right_key`, `level`) VALUES (1, 'Овощи', 2, 9, 2), (2, 'Картошка', 3, 4, 3), (3, 'Капуста', 5, 6, 3), (4, 'Буряк', 7, 8, 3), (5, 'Фрукты', 10, 17, 2), (6, 'Банан', 11, 12, 3), (7, 'Киви', 13, 14, 3), (8, 'Яблоко', 15, 16, 3), (9, 'Ягоды', 18, 21, 2), (10, 'Арбуз', 19, 20, 3), (11, 'Другое', 22, 23, 2), (12, 'Еда', 1, 24, 1);
я пару раз пытался сделать многоуровневые категории через нестеды)) потом каждый раз стирал все и делал через id pid и рекурсию))
@Алекс8 многие почему то рекомендуют Nested Sets --- Добавлено --- Я понял, что выводится отсортированный список по полю level, больше пока ничего не понял
Ну а подумать? Либо преобразовать в рекурсивный массив, либо вывести с помощью стеков. Вот, я когда-то изобретал: PHP: <?php $a = [ ["id" => 1, "name" => 1, "level" => 1], ["id" => 2, "name" => 2, "level" => 2], ["id" => 3, "name" => 3, "level" => 2], ["id" => 4, "name" => 4, "level" => 3], ["id" =>5, "name" => 5, "level" => 4], ["id" => 6, "name" => 6, "level" => 2], ]; $s = [$a[0]["level"]]; echo "<ul>"; foreach ($a as $ind => $ae) { if ($ae["level"] > $s[count($s) - 1]) { $s[] = $ae["level"]; echo "<ul>"; } elseif ($ae["level"] < $s[count($s) - 1]) { while ($ae["level"] < $s[count($s) - 1]) { echo "</li></ul></li>"; array_pop($s); } } if ($ind > 0 && $ae["level"] === $a[$ind - 1]["level"]) { echo "</li>"; } echo "<li>$ae[name]"; } while (count($s)) { echo "</li></ul>"; array_pop($s); } Может можно и проще --- Добавлено --- По полю left Потому что всё дерево выбирается одним запросом, т.е. чтоб избежать необходимости запросов в рекурсивной функции. Ты же знаешь, что в цикле и в рекурсии запросы не стоит использовать?
Проще, но менее эффективный, так как приходится делать запросы из рекурсивной функции. Здесь кода больше, но для больших деревьев потенциально будет выигрыш по времени из-за сокращения числа запросов --- Добавлено --- Этот код же тоже не шибко сложный, на самом деле, и отработает очень быстро --- Добавлено --- Т.е. ещё раз - зачем придумали nested sets - чтобы читать всё дерево одним запросом, со всеми листьями. C pid тоже есть метод, если ты хранишь порядок, т.е. если можешь одним запросом получить всё дерево, у которого потомки будут гарантированно идти после предков. --- Добавлено --- @Dimon2x, почитай что-нибудь не про PHP, а про алгоритмы. Дональда Кнута вряд ли потянешь (я и сам не потянул в своё время, к сожалению), а вот Никласа Вирта "Алгоритмы + структуры данных = программы" стоит почитать. Там, конечно, ещё не ООП, но ООП - это тоже в конечном итоге алгоритм, поэтому всё равно не помешает. --- Добавлено --- Я смог дойти до этого алгоритма сам, поскольку знал, что такое стек, что такое очередь, чем отличаются, как организовать. Работал с бинарными деревьями в ВУЗе (хоть его и не закончил), в нужный момент такие знания выручают.
может фантик оборачивает саму конфету ? --- Добавлено --- PHP: foreach ( $a AS [ 'name' => $name, 'level' => $lvl ] ) { echo str_repeat ( '-', $lvl ) . " $lvl" . PHP_EOL; } --- Добавлено --- или функция сама себя просит, уменьшая лвл
@MouseZver Ну обычно задача отобразить дерево в виде древовидного html, как вложенные <ul> в моём примере, а если достаточно вывести чёрточки - то да, можно и как ты Если можешь предложить более элегантное решение, дающее тот же результат, что приведённый мной код, буду только рад почитать, я не претендую на лучшее из возможных решений. И, если я при воспроизведении не ошибся (проверял только для тех данных, что в коде, сейчас), правильно обрабатывает скачок уровней, когда, к примеру, после 4 уровня идёт снова 1-й Pascal или Modula 2, в зависимости от редакции, которые он же и изобрёл. PHP тогда даже в проекте не было, когда он эти книги писал Но эти языки легко понимать. там всё - английские слова, начало блока begin, конец - end, и в принципе, не в языке дела, а в объяснении логики алгоритмов и логики работы со структурами данных. Не обязательно даже запускать там примеры, можно просто разобраться в сути происходящего. Есть Дональд Кнут, там вообще без кода, но там реально очень сложная книга, хотя и даёт +500000 к скиллу программиста, если осилить. Повторюсь, я не осилил в своё время. Может быть всё-таки найду время, хотя сейчас просто на другое внимание уходит, не до возврата к основам. Не, это для меня слишком. Политех, тех. кибернетика. Углубляться в биографию, почему не закончил, не буду.
@mkramer сделал Спойлер: Логика HTML: l=0 l=0 < lvl=1 <ul><li> 1 l=1 < lvl=2 <ul><li> 2 l=2 === lvl=2 </li><li> 3 l=2 < lvl=3 <ul><li> 4 l=3 < lvl=4 <ul><li> 5 l=4 > lvl=2 { </li></ul> </li></ul> <li> } 6 register_shutdown { $l=2 (</li></ul>) (</li></ul>) } Спойлер: . PHP: <?php $a = [ ["id" => 1, "name" => 1, "level" => 1], ["id" => 2, "name" => 2, "level" => 2], ["id" => 3, "name" => 3, "level" => 2], ["id" => 4, "name" => 4, "level" => 3], ["id" =>5, "name" => 5, "level" => 4], ["id" => 6, "name" => 6, "level" => 2], ["id" => 7, "name" => 7, "level" => 7], ["id" => 8, "name" => 8, "level" => 2], ]; function d ( array $arr ) { $l = 0; foreach ( $arr AS [ 'name' => $name, 'level' => $lvl ] ) { if ( $l < $lvl ) { echo str_repeat ( '<ul><li>', $lvl - $l ) . $name; $l = $lvl; } elseif ( $l > $lvl ) { echo str_repeat ( '</li></ul>', $l - $lvl ) . '<li>' .$name; $l = $lvl; } else { echo '</li><li>' . $name; } } echo str_repeat ( '</li></ul>', $l ); } echo d ( $a ) . PHP_EOL; P.s: 7 слишком далеко кажется ? считаем с конца.
Колледж ВГППК - IT. Воронеж Информатика 3, не потому что я ее не понимал, а бунтовал из - за направлении "помощь вбития артикулов книжек для библиотеки". Место этого я срал на все мнения и угрозы, делал свой самый первый проект ICQ конструктор аськи изучая php. (2011) После я действительно понимал что некоторые предметы мне в жизни не впились. После обеда ВСЕГДА сбегал. Физ-ра 0 походов - она мне вообще не интересна. ( не потому что я дрыщь - у меня бывшая работа с керамической плиткой была, файлы с наклееной плиткой ( фулловые в обеих сторонах) по 100кг поднимаю в одно рыло. ). Практика IT всегда 5 - приходили в 9 часов и в 2 Уё. Рисовали в CoreDraw, фотошоп, анимацию, Exel World (BD) всякая дичь, которую за 2 часа сделаю - требую добавки (дальше по программе). Если нет, начинаю преподавалку молодую у нас троллить - у каждого компа установлен был агент наблюдения. Я его нахрен крашил батником, т.к диспетчер был недоступен для нас смертных. И занимался своими делами. Уйти пораньше нельзя было. После НГ я жестко заболел и практику всю пропустил. Зачеты небыли закрыты. В Феврале 2014 помоему, с довольным лицом иду в зав. отделение. "Всем адиос". --- Добавлено --- Больше всего запоминалось в чушке - УВК. Cyка да эти клоуны вообще хотят слушать мнения каждого ? Каждая ЧСВшная препод-баба, пыталась набить себе репутацию перед начальством, одна даже кривлялась рыжая бестия ( физика ). Старшекурсницы выбегая оттуда, рыдали. О боже "исключат" - великая потеря в Рашке. Все равно пойдешь в пятерочку. --- Добавлено --- если вобьете первую строчку в поисковик, уведите картинку где по середине старпер держит красную Т.Бумагу - Халерик (помидорный) с Завышенной ( до конечного края космоса ) ЧСВ, преподки из за него тоже рыдали. Всего лишь басс в голосе, а так тряпка. Почему дальше не пошел учиться ? А вот тут потребности в деньгах пошли. Можно было учиться и работать - (ага удачи). Можно работать и подрабатывать. --- Добавлено --- У меня до часу фантазии с интересной логикой были, забил до утра.
Посмотрел ютюб чушка своего, моя группа не обнаружена не единый человек. Нету выпуска, ничего, хоть и были там "умники" 2. 2018 IT отдел Delete.