Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: разработка для Web > Зависание скрипта при проходе по массиву


Автор: Chuck 15.9.2008, 20:21
Доброго времени суток, друзья.

Есть в БД таблица
sections
---------------------
section_id
section_parent
section_name

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

Был написан вот такой вот тестовый скрипт:
Код

#!C:\perl\bin\perl -w

use CGI;
use CGI::Carp 'fatalsToBrowser';
use DBI;
use strict;
use utf8;
use warnings;

# Dirs ...
our $root_dir = 'E:/work/current/freelance/ndvakt.uz';
our $tempales_dir = $root_dir . '/cgi-bin/templates';

my @sections = ();

sub get {
    my $parent = shift;
    foreach my $section (@sections) {
        if ($parent eq $section->{section_parent}) {
            my $sid = $section->{section_id};
            my $s = $sections[$sid];
            print %{$s};
            get($sid);
        }
    }
}


# Connect to database ...
our $dbc = DBI->connect('DBI:mysql:ndvakt:localhost:3306', 'root', 'psw123');
$dbc->do('SET NAMES utf8');

print "Content-type: text/html;charset=utf-8\n\n";
my $res = $dbc->prepare('SELECT * FROM sections');
$res->execute();
while (my $section = $res->fetchrow_hashref()) {
    my $sid = $section->{'section_id'};    
    $sections[$sid] = $section;
}
$res->finish();

get(20);


Однако, при выполнении данного кода перл-интерпретатор просто зависает. 

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

Автор: nitr 16.9.2008, 01:00
Chuck, считаю что зависание в вашем рекурсив.обходе - sub get.

Автор: Chuck 24.9.2008, 09:15
Простите, не понял. Я понимаю, что зависает именно в этой функции, однако, как этого избежать?

Автор: nitr 24.9.2008, 16:13
покажите здесь
Код
...
use Data::Dumper 'Dumper';

...
print Dumper(@sections);
#get(20);

Автор: Chuck 3.10.2008, 23:54
Извиняюсь, что пропал, была командировка. 

Дампер вывел вполне адекватные результаты, на мой взгляд.

На что я должен обратить внимание?

Код

$VAR1 = undef;
$VAR2 = {
          'template' => 'admin:mainpage',
          'section_alias' => 'admin',
          'section_order' => '0',
          'section' => 'Админ панель',
          'section_id' => '1',
          'show_menu' => '1',
          'default_section' => '0',
          'section_parent' => '0',
          'section_level' => '1'
        };
$VAR3 = {
          'template' => 'admin:users',
          'section_alias' => 'users',
          'section_order' => '0',
          'section' => 'Пользователи',
          'section_id' => '2',
          'show_menu' => '1',
          'default_section' => '0',
          'section_parent' => '1',
          'section_level' => '2'
        };
$VAR4 = {
          'template' => 'admin:sections',
          'section_alias' => 'sections',
          'section_order' => '0',
          'section' => 'Секции',
          'section_id' => '3',
          'show_menu' => '1',
          'default_section' => '0',
          'section_parent' => '1',
          'section_level' => '2'
        };
$VAR5 = {
          'template' => 'admin:content',
          'section_alias' => 'content',
          'section_order' => '0',
          'section' => 'Контент',
          'section_id' => '4',
          'show_menu' => '1',
          'default_section' => '0',
          'section_parent' => '1',
          'section_level' => '2'
        };
$VAR6 = undef;
$VAR7 = undef;
$VAR8 = undef;
$VAR9 = undef;
$VAR10 = undef;
$VAR11 = undef;
$VAR12 = undef;
$VAR13 = undef;
$VAR14 = undef;
$VAR15 = undef;
$VAR16 = undef;
$VAR17 = undef;
$VAR18 = undef;
$VAR19 = undef;
$VAR20 = undef;

Автор: ginnie 4.10.2008, 09:12
Chuck, мне кажется, что с такими данными у Вас в строке

Код

if ($parent eq $section->{section_parent}) {


должно быть сообщение об ошибке, про невозможность использования undef в качестве ссылки на хэш.
Кроме того, в этой строке правильнее использовать == вместо eq, т.к. сравниваются числовые значения.

Автор: nitr 4.10.2008, 11:42
Chuck, тогда объясните, что должна делать данная функция smile ?
Например, из вашего скрипта видно, что необходимо вернуть "секции", у которых в "родителях" section_parent=20.
Но зачем тут "на первый взгляд" рекурсия?

Если всё же верно:
Цитата(Chuck @  15.9.2008,  20:21 Найти цитируемый пост)
Задача состоит в том, чтобы написать функцию, которая бы вытаскивала из этого списка только те секции, section_parent которых равен определенному значению.

ТО:
  Из sub get уберите get($sid);.

Добавлено через 3 минуты и 37 секунд
А если все секции и внутри веток, то:
 У вас неверно создается древовидная структура!

Добавлено через 6 минут и 13 секунд
Я всегда привожу примерную структуру, на которой можно выявлять некоторые ошибки...
Вот как пример (сильно не бить за стиль... утро smile) ):
Код
#!/usr/bin/perl
use strict;
use warnings;

my @sections = (
    {
        'section_parent' => '0', 
        'section_id' => '0',
        'section' => 'Parent',
    },
    {
        'section_parent' => '0', 
        'section_id' => '1',
        'section' => 'Menu',
    },
    {
        'section_parent' => '1', 
        'section_id' => '2',
        'section' => 'Sub Menu1',
    },
    {
        'section_parent' => '2', 
        'section_id' => '3',
        'section' => 'Sub Menu1_1',
    },
    {
        'section_parent' => '2', 
        'section_id' => '4',
        'section' => 'Sub Menu1_2',
    },
    {
        'section_parent' => '4', 
        'section_id' => '5',
        'section' => 'Menu',
    },
    {
        'section_parent' => '4', 
        'section_id' => '6',
        'section' => 'Sub Menu1_1_2',
    },
    {
        'section_parent' => '6', 
        'section_id' => '7',
        'section' => 'Sub Menu1_1_1_2',
    },
    {
        'section_parent' => '7', 
        'section_id' => '8',
        'section' => 'Menu',
    },
    {
        'section_parent' => '6', 
        'section_id' => '9',
        'section' => 'Sub Menu2_1_1_2',
    },
    {
        'section_parent' => '9', 
        'section_id' => '10',
        'section' => 'Menu',
    },
);

sub get {
    my $parent = shift;
    foreach my $section (@sections) {
        if ( $parent == $section->{section_parent} ) {
            my $sid = $section->{section_id};
            my $s = $sections[$sid];
            print %{$s}, "\n";
            get($sid);
        }
    }
}

get(1);

Автор: Chuck 4.10.2008, 13:02
ginnie, вы правы, но скрипт все равно зависает.

Мне кажется, это потому что я использую fetchrow_hashref();
И не правильно работаю со ссылками. Но вот как тут разобраться - не понимаю.

nitr, ваш скрипт работает, и сопоставив функции get() мою и вашу, я понял, что проблема не в ней, а в том, что я храню в массиве ссылки.

Автор: nitr 4.10.2008, 13:26
Chuck, я склоняюсь к формированию структуры!
Если немного измените мой скрипт, он сразу же зависнет smile (где менять - даю вам подумать)

Добавлено через 53 секунды
Подскажу - в структуре, а точнее @sections

Добавлено через 1 минуту и 32 секунды
Цитата(Chuck @  4.10.2008,  13:02 Найти цитируемый пост)
а в том, что я храню в массиве ссылки.

это нормально, что вы там ещё хранить хотели ;) ?

Автор: Chuck 6.10.2008, 07:47
Доброе утро, на ум приходит только одно: элементы массива реализовать ссылками на хеши.

Автор: unicross 6.10.2008, 12:27
Добавьте одну строку в функцию get()

Код

       next if ($section == undef);



Код

sub get {
    my $parent = shift;
    foreach my $section (@sections) {
        next if ($section == undef);
        if ( $parent == $section->{section_parent} ) {
            my $sid = $section->{section_id};
            my $s = $sections[$sid];
            print %{$s}, "\n";
            get($sid);
        }
    }
}

Автор: ginnie 6.10.2008, 13:03
unicross, это где же Вас такому научили?

Код

next if ($section == undef);


у нас все пишут

Код

next if (!defined $section);


или

Код

next unless (defined $section);

Автор: unicross 6.10.2008, 14:20
Да. Так будет правильнее

Код

next if (!defined $section);


Sorry. Еще не проснулся...

Автор: nitr 6.10.2008, 17:46
Цитата(Chuck @  6.10.2008,  07:47 Найти цитируемый пост)
Доброе утро, на ум приходит только одно: элементы массива реализовать ссылками на хеши. 

у вас иначе? smile "тыкните пальцем" где не так уже...

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

Цитата(nitr @  4.10.2008,  11:42 Найти цитируемый пост)
Из sub get уберите get($sid);.

что вам это дает? Проверьте.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)