LINUX.ORG.RU

Обработка деревьев

 ,


0

1

Есть таблица массив

id    pid    cat
---------------------------
1      1     Animals
2      2     Flowers
3      1     Cat
4      1     Dog
5      2     Forget me not
6      3     Begemot 
---------------------------

Необходимо получить массив:

id    pid    cat
---------------------------
1      1     Animals
2      2     Flowers
3      1     Animals\Cat
4      1     Animals\Dog
5      2     Flowers\Forget me not
6      3     Animals\Cat\Begemot 
---------------------------

Как это лучше сделать на perl?

★★★★★

В perl нет двумерных массивов, соответственно таблицу нужно представить в виде массива массивов:

my @a=(
  [1,1,'Animals'],
  [2,2,'Flowers'],
  [3,1,'Cat'],
);

map {
  $_->[2]=$a[$_->[1]]->[2].'/'.$_->[2];
} @a;

use Data::Dumper;
say Dumper \@a;
Если таблица изначально не отсортирована по id, то стоит добавить sort перед map

disarmer ★★★
()
Последнее исправление: disarmer (всего исправлений: 1)
Ответ на: комментарий от disarmer

Ошибся в мапе, надо так:

map {
  $_->[2]=$a[$_->[1]-1]->[2].'/'.$_->[2];
} grep {$_->[0]!=$_->[1]} @a;

disarmer ★★★
()
Ответ на: комментарий от disarmer

спасибо, а не подскажите как организовать хеш для этого массива. Т.е. я делаю запрос к БД:

$sth = $dbh->prepare("select id,pid,cat from mytable"); 
и хочу получить хеш
while ($ref = $sth->fetchrow_arrayref) {
$hash[$ref[0]]['pid']=$ref[2];
$hash[$ref[0]]['cat']=$ref[2];
}
Правильно делаю?

int13h ★★★★★
() автор топика
Последнее исправление: int13h (всего исправлений: 1)
Ответ на: комментарий от int13h

нет, можно получать ссылку на хеш:

while ($ref = $sth->fetchrow_hashref) {
  say $ref->{cat};
}

disarmer ★★★
()
Ответ на: комментарий от int13h

Это вообще какой то странный синтаксис:

$hash[$ref[0]] - обращение к элементам хеша осуществляется через фигурные скобки {}, а не квадратные []

['pid'] - то же самое, видимо фигурные скобки нужны

][ - так нельзя, если мы получаем ссылку на объект, то чтобы обратиться к вложенному элементу нужно использовать ]->[

$ref[2] - тоже самое, если $ref это ссылка на массив, то обращаться нужно $ref->[2]

disarmer ★★★
()
Ответ на: комментарий от disarmer

Чтобы сориентироваться в типах, можно поиграться с Dumper, например:

my @a=[1,2,{a=>7,b=>8,c=>[4,5]}];
use Data::Dumper;
say Dumper \@a;

disarmer ★★★
()

а есть гарантия что при выборке не будет так, что pid будет указывать на родителя, который еще не выбрался?

pef-secure
()

делается «деревянная» структура в хеше, в процессе чтения в хеш айди вносятся указатели на соответствующие структуры, чтобы потом не искать их. для показа придётся сделать рекурсивный (или его аналог) обход. псевдокод:

my %ids;
my %tree;
while(my $row=$sth->selectrow_hashref) {
  $ids{$row->{id}} = {childs => [], pid => $row->{pid}, cat => $row->{cat}};
  if ($row->{id} == $row->{pid}) {
    $tree{$row->{id}} = $ids{$row->{id}};
  } else {
    die "сын раньше родителя!" if not exists $ids{$row->{pid}};
    push @{$ids{$row->{pid}}{childs}}, $ids{$row->{id}};
  }
}

%ids — временный хеш, его можно забыть, а %tree будет содержать что тебе надо.

pef-secure
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.