Reputation: 929
I have a file like
abc->bcd, efg, hij
bcd->ijk, lmn, ipl
efg->kfg, iop, nkl
lmn->opq, stv, imn
the nested output should be created from this like
abc
bcd
ijk
lmn
opq
stv
imn
ipl
efg
kfg
iop
nkl
hij
I am not very sure how to handle this in perl with recursive function to find any level of nesting. Anyone's help much appreciated.
I have tried with following code, but it gives only one level
my $k = 0;
while ($k <=$#array1)
{
if ($array1[$k]=~m/(.[^->]*)->(.[^\n]*)/)
{
$val = $1;
$val1 = $2;
push @check, $val;
print $val;
my @array2=split /,/,$val1;
foreach my $newid (@array2)
{
push @check1, $newid;
print $newid, "\n";
}
}
$k++;
}
Upvotes: 0
Views: 282
Reputation: 126752
It's another directed graph! They seem popular recently
You need the Graph
module, which will allow you to build a tree of edges and vertices (nodes and connections) and then traverse it to obtain your printout
This program does exactly that with your sample data. Once the graph is built, I test whether it's cyclic to avoid an endless loop and then call my recursive subroutine print_vertex
for all source vertices
A source vertex is one that has successors but no predecessors (children but no parent). So it's a root of the tree. I've used a for
loop in case the data has more than one root, but your data has only one such vertex: abc
use strict;
use warnings 'all';
use feature 'say';
use Graph;
my $g = Graph->new(directed => 1);
while ( <DATA> ) {
my ($from, @to) = /[^\s>,-]+/g;
$g->add_edge($from, $_) for @to;
}
if ( my @cycle = $g->find_a_cycle ) {
die sprintf "Graph contains a cycle: %s\n", join(' >> ', @cycle, $cycle[0]);
}
print_vertex($_) for $g->source_vertices;
sub print_vertex {
my ($v, $indent) = (@_, 0);
printf "%s%s\n", ' ' x $indent, $v;
print_vertex($_, $indent+1) for $g->successors($v);
}
__DATA__
abc->bcd, efg, hij
bcd->ijk, lmn, ipl
efg->kfg, iop, nkl
lmn->opq, stv, imn
abc
efg
iop
kfg
nkl
bcd
lmn
stv
opq
imn
ijk
ipl
hij
Upvotes: 4
Reputation: 41905
... when I try this, the order has changed in the output...can you help me on how to retain the orders?
Recursive solution in pure Perl sans module:
use strict;
use warnings;
my %children;
my $patriarch;
while (<DATA>) {
chomp;
my ($parent, @children) = split /[->, ]+/;
$children{$parent} = \@children;
$patriarch = $parent unless defined $patriarch;
}
sub print_family {
my ($parent, $indentation) = (@_, '');
print($indentation, $parent, "\n");
if (exists($children{$parent})) {
foreach my $child (@{$children{$parent}}) {
&print_family($child, $indentation . "\t");
}
}
}
&print_family($patriarch)
__DATA__
abc->bcd, efg, hij
bcd->ijk, lmn, ipl
efg->kfg, iop, nkl
lmn->opq, stv, imn
Produces:
abc
bcd
ijk
lmn
opq
stv
imn
ipl
efg
kfg
iop
nkl
hij
Upvotes: 1