Модераторы: skyboy, MoLeX, Aliance, ksnk
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Оцените скрипт построения списка-дерева, Алгоритм очень шустрый (2 функции) 
:(
    Опции темы
LittleFuntik
Дата 13.6.2009, 17:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 37
Регистрация: 8.8.2007
Где: Украина, Чернигов

Репутация: нет
Всего: нет



Захотел сам, не смотря ни на какие исходники написать скрипт, формирующий список-дерево. Не пугайтесь кода! Он очень шустрый. Я попытался сделать без классов и глобальных переменных.

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

Код

function tree_ul(&$a,$pId=0,$next=false){
    if($next==false){$_r = $a;}
    foreach($a as $i => $v){
        if( isset($v) && $pId == $v['pId'] ){
            $r .= '<li>';    
            $r .= $v['title'];
            $Id = $v['Id'];
            unset($a[$i]);
            $r .= tree_ul($a,$Id,true);
            $r .= '</li>'; 
        }
    }
    if( $next==false && sizeof($a) > 0 ){
        foreach($a as $v){
            $r .= '<li>';    
            $r .= $v['title'];
            $Id = $v['Id'];
            unset($a[$i]);
            $r .= tree_ul($a,$Id,true);
            $r .= '</li>'; 
        }
    }
    if( trim($r) != '' ){
        $r = '<ul>'.$r.'</ul>';
    }
    if($next==false){$a = $_r;}
    return $r;
}


Эту функцию легко использовать, например этот скрипт возвратит такой результат:

Код

$r[0] = array('Id' => 4,'pId' => 2,'title' => '111');
$r[1] = array('Id' => 5,'pId' => 4,'title' => '222');
$r[2] = array('Id' => 6,'pId' => 100,'title' => '333');
$r[3] = array('Id' => 7,'pId' => 6,'title' => '444');
$r[4] = array('Id' => 1,'pId' => 0,'title' => 'Книги для велосипедиста');
$r[5] = array('Id' => 2,'pId' => 1,'title' => 'Нужные');
$r[6] = array('Id' => 3,'pId' => 1,'title' => 'Свалка книг');
echo tree_ul($r);


Видим такое:
user posted image


Заметьте, что ветки, в которых родитель не нашелся, тоже отображаются, но в конце. И еще, если эти ветки имеют потомков, то они выводятся, как потомки.

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

Код

function tree_ul_new(&$a,&$tpl=null,$pId=0,$next=false,&$lvl=0,&$li_number=0){
    $lvl++;
    
    if( !$tpl['default'] ){$tpl['default']=array('ul'=>'<ul>','/ul'=>'</ul>','li'=>'<li>{li_number}) {title}','/li'=>'</li>');}
    
    if($next==false){$_r = $a;}
    foreach($a as $i => $v){
        if( $pId == $v['pId'] ){
            $Item = $v;
            $childrens = 0;
            foreach($a as $k1 => $v1){if($v1['pId']==$a[$i]['Id']){$childrens++;}}
            if( trim($tpl[$i]) != '' ){ $t = $tpl[$i];}else{$t=$tpl['default'];}
            if( $childrens > 0 ){
                if( isset($t['li_']) ){$t['li']=$t['li_'];}
                if( isset($t['/li_']) ){$t['/li']=$t['li_'];}
            }
            $li_number++;
            $r1 = $t['li'];
            foreach($Item as $k1 => $v1){ $r1 = str_replace('{'.$k1.'}',$v1,$r1); }
            $r1 = str_replace(array('{lvl}','{childrens}','{li_number}'),array($lvl,$childrens,$li_number),$r1);
            
            $r .= $r1;
            unset($a[$i]);
            $r .= tree_ul_new($a,&$tpl,$Item['Id'],true,$lvl,$li_number);
            
            $r1 = $t['/li'];
            foreach($Item as $k1 => $v1){ $r1 = str_replace('{'.$k1.'}',$v1,$r1); }
            $r1 = str_replace(array('{lvl}','{childrens}','{li_number}'),array($lvl,$childrens,$li_number),$r1);
            
            $r .= $r1;
        }
    }
    if( $next==false && sizeof($a) > 0 ){
        foreach($a as $i => $v){
            if( trim($tpl[$i]) != '' ){ $t = $tpl[$i];}else{$t=$tpl['default'];}
            
            $childrens = 0;
            foreach($a as $k1 => $v1){if($v1['pId']==$a[$i]['Id']){$childrens++;}}
            
            $li_number++;
            $r1 = $t['li'];
            foreach($v as $k1 => $v1){ $r1 = str_replace('{'.$k1.'}',$v1,$r1); }
            $r1 = str_replace(array('{lvl}','{childrens}','{li_number}'),array($lvl,$childrens,$li_number),$r1);
            
            $r .= $r1;
            unset($a[$i]);
            $r .= tree_ul_new($a,&$tpl,$v['Id'],true,$lvl,$li_number);
            
            $r1 = $t['/li'];
            foreach($v as $k1 => $v1){ $r1 = str_replace('{'.$k1.'}',$v1,$r1); }
            $r1 = str_replace(array('{lvl}','{childrens}','{li_number}'),array($lvl,$childrens,$li_number),$r1);
            
            $r .= $r1;
        }
    }
    if( trim($r) != '' ){ $r = $tpl['default']['ul'].$r.$tpl['default']['/ul']; }
    if($next==false){$a = $_r;}
    $lvl--;
    return $r;
}


А вот пример использования:

Код

$ro[0] = array('Id' => 4,'pId' => 2,'title' => '111');
$ro[1] = array('Id' => 5,'pId' => 4,'title' => '222');
$ro[2] = array('Id' => 6,'pId' => 100,'title' => '333');
$ro[3] = array('Id' => 7,'pId' => 6,'title' => '444');
$ro[4] = array('Id' => 1,'pId' => 0,'title' => 'Книги для велосипедиста');
$ro[5] = array('Id' => 2,'pId' => 1,'title' => 'Нужные');
$ro[6] = array('Id' => 3,'pId' => 1,'title' => 'Свалка книг');

$z['default']=array('ul'=>'<ul>','/ul'=>'</ul>','li'=>'<li>{li_number}) {title} (уровень_списка={lvl}) Id={Id}','/li'=>'</li>');
$z['1']['/li']='<hr /></li>';
$z['2']['li']='<li>{title} (кол-во потомков: {childrens}) Id={Id}';

        echo tree_ul_new($ro,$z);
    }
}


Результат выполнения:
user posted image

Здесь в шаблонах можно указывать дополнительные переменные:
 - {li_number} текущий номер элемента, начиная считать с первого;
 - {childrens} количество потомков в текущего элемента;
 - {lvl} уровень вложенности текущего элемента списка.

$z['2']['li'] ...
 - 'li' - указываем шаблон для 2-го элемента списка, который не имеет потомков;
 - 'li_' - указываем шаблон для 2-го элемента списка, который имеет потомков. Если шаблон не указать, то используется предыдущий шаблон;

$z['default'] - здесь храним стандартный шаблон. Вот так вот.

Хочу узнать свой уровень программирования по 100 бальной шкале smile

...
Подправил, была проблема с $childrens в неопределенных(нижних) элементах(смотрите 2-ю картинку "потомков: 2).

Это сообщение отредактировал(а) LittleFuntik - 13.6.2009, 17:53
PM MAIL WWW   Вверх
bars80080
Дата 14.6.2009, 09:35 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


прапор творюет
****
Награды: 1



Профиль
Группа: Завсегдатай
Сообщений: 12022
Регистрация: 5.12.2007
Где: Königsberg

Репутация: 71
Всего: 315



ну да, а в профи как раз такие вопросы обсуждают и дают очки, как на шоу славы

работает? не тормозит? делает то что тебе нужно?
ну и славненько
PM MAIL WWW   Вверх
ksnk
Дата 14.6.2009, 11:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 96
Всего: 386



Хочется добавить, что в пятницу (и в эту,по инерции), народ еще более-менее активно посещает форум, а субботу-воскресенье - традиционно отдыхает.

Ну а по сути, шаблон - это, как правило, отдельная вещь (отдельный файл), которая(ый) в общем случае и пишется даже отдельным человеком. Мне сложно представить как бы я смог объяснить верстальщику, что при верстке именно вот этого участка нужно лезть куда-то в код и писать какие-то странные строчки на php.

Можно посмотреть примерный синтаксис какого-нибудь шаблонизатора (Cмарти, к примеру и для контраста шаблонизатор от CI) и написать шаблон по принятым у верстальщиков правилам. Потом попробовать, как массив влезает в этот шаблон...

Это я , собственно, про то, что вторая часть просто лишняя...


--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
MoLeX
Дата 15.6.2009, 06:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Местный пингвин
****


Профиль
Группа: Модератор
Сообщений: 4076
Регистрация: 17.5.2007

Репутация: 46
Всего: 140




M
MoLeX



Модератор: Автор какой смысл было размещать эту тему в разделе РНР: Профи?




Добавлено через 11 секунд
перенесено


--------------------
Amazing  smile 
PM MAIL WWW ICQ   Вверх
s0lman
Дата 11.8.2009, 14:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Белый и лохматый
**


Профиль
Группа: Участник
Сообщений: 637
Регистрация: 1.11.2007
Где: Ukraine

Репутация: 9
Всего: 29



В общем, мне тут нечто подобное понадобилось, отчего наткнулся в поиске на это творение.
Вот только никок не пойму - как у него выполняется рекурсивный подъем? (вторую ф-ю не смотрел)
И не могу предположить, как у него получился вывод "Свалка книг" - это код корявый, или у меня руки кривые? ;)


--------------------
Когда я уже выучусь на волшебника? :(
PM   Вверх
s0lman
Дата 12.8.2009, 00:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Белый и лохматый
**


Профиль
Группа: Участник
Сообщений: 637
Регистрация: 1.11.2007
Где: Ukraine

Репутация: 9
Всего: 29



В общем, дома код заработал. Тут же подключился к рабочей машине, коды перекинул - как и раньше: выполняется до момента, когда нужно подниматься на уровень выше, т.е. на этом примере последняя выводимая запись будет 222.
У кого есть какие соображения по этому поводу?


--------------------
Когда я уже выучусь на волшебника? :(
PM   Вверх
SneG0K
Дата 12.8.2009, 00:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Max Mara
***


Профиль
Группа: Завсегдатай
Сообщений: 1887
Регистрация: 1.12.2007
Где: Wis Dells

Репутация: 7
Всего: 54



LittleFuntik, а как по мне, так круче будет брать код из XML
Код

function generateMenu($xmlFile) {
    if (!$xml = simplexml_load_file($xmlFile)) 
        generate_error("Ошибка при инициализации");
        
    $menu = array();    
    foreach ($xml->cat as $cats) {
        $tmp = array();
        $tmp['title'] = (string) $cats->attributes()->title;
        $tmp['link'] = (string) $cats->attributes()->link;
        $tmp['id'] = (string) $cats->attributes()->id;
        
        $tmp['body'] = array();    
        foreach ($cats->sub as $body) {
            $sub_tmp = array();
            $sub_tmp['id'] = (string) $body->attributes()->id;
            $sub_tmp['link'] = (string) $body->attributes()->link;
            $sub_tmp['title'] = (string) $body->attributes()->title;            
            $tmp['body'][] = $sub_tmp;
        }
        $menu[] = $tmp;
    }
        return $menu;
}


Код

<?xml version="1.0" encoding="utf-8"?>
<menu>
    <cat id="0" link="#" title="О компании">
        <sub id="0" link="#" title="Ссылка 1" />
        <sub id="1" link="#" title="132" />
    </cat>
    <cat id="1" link="#" title="Еще что-то">
        <sub id="0" link="#" title="12423" />
        <sub id="1" link="#" title="123142" />
    </cat>
</menu>


А круче этого только яйца.

Добавлено через 1 минуту и 51 секунду
Цитата(LittleFuntik @  13.6.2009,  16:47 Найти цитируемый пост)
Хочу узнать свой уровень программирования по 100 бальной шкале

Садись! два балла ^_^
PM WWW Skype   Вверх
Ипатьев
Дата 12.8.2009, 09:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2232
Регистрация: 5.7.2009

Репутация: 28
Всего: 37



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

Лично я бы сделал в два этапа. Сначала получил дерево, а потом развернул его в плоский массив.
чтобы в массиве было что-то вроде
open
item
item
open
item
close
close
item
close

И уже этот массив передавать шаблонизатору.

Добавлено @ 09:35
Учитывая, что вся относительная "сложность" алгоритма состоит в необходимости закрывающего тега, то имеет смысл подумать о другом варианте визуализации. Не списками, а, скажем, отступами. Тогда массив получится гораздо проще, и в нем нужно будет указывать только уровень вложенности элемента.

Это сообщение отредактировал(а) Ипатьев - 12.8.2009, 09:35
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "PHP"
Aliance
IZ@TOP
skyboy
SamDark
MoLeX

Новичкам:

  • PHP редакторы собираются и обсуждаются здесь
  • Электронные книги по PHP, документацию можно найти здесь
  • Интерпретатор PHP, полную документацию можно скачать на PHP.NET

Важно:

  • Не брезгуйте пользоваться тегами [code=php]КОД[/code] для повышения читабельности текста/кода.
  • Перед созданием новой темы воспользуйтесь поиском и загляните в FAQ
  • Действия модераторов можно обсудить здесь

Внимание:

  • Темы "ищу скрипт", "подскажите скрипт" и т.п. будут переноситься в форум "Web-технологии"
  • Темы с именами: "Срочно", "помогите", "не знаю как делать" будут УДАЛЯТЬСЯ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, IZ@TOP, skyboy, SamDark, MoLeX, awers.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0850 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.