ravish has asked for the wisdom of the Perl Monks concerning the following question:
Hi,
I need help in sorting of array. My array is like this.
@array = (
{
level => 1,
department = 'Office of President',
},
{
level => 2,
department = 'Recruiting',
},
{
level => 2,
department = 'Software',
},
{
level => 3,
department = 'MIS',
},
{
level => 3,
department = 'System Operations',
},
{
level => 2,
department = 'Pipe line',
},
);
basically this is made for tree like structure, when i print this
array , it prints like this :
Office of the President
Recruiting
Software
MIS
System Operations
PipeLine
Currently the department is not sorted alphabetically beacuse my array
is created on the basis of level and it is in sequence.
Now i want to sort the department alphabetically. How will
i do this.
I want this array print like this :
Office of the President (Make this as base level)
PipeLine
Recruiting
Software
MIS
System Operations
etc.....
Thanks
update (broquaint): added <code> tags
Re: Logic for sorting of this given array
by Zaxo (Archbishop) on Aug 28, 2003 at 05:35 UTC
|
The logic for multiple sorting is as follows,
my @sorted = sort {
$a->{'level'} <=> $b->{'level'}
||
$a->{'department'} cmp $b->{'department'}
} @array;
That works by the lazy evaluation of logical operators. If comparison by level is not a tie, the department comparison is not made.
After Compline, Zaxo | [reply] [d/l] |
Re: Logic for sorting of this given array
by gmax (Abbot) on Aug 28, 2003 at 10:58 UTC
|
If you want a tree, why don't you use a real tree structure?
Tree::DAG_Node is meant for cases like this one.
#!/usr/bin/perl -w
use strict;
use Tree::DAG_Node;
my $org = Tree::DAG_Node->new; # the root
$org->name('Office of President'); # name it
$org->new_daughter->name('Recruiting'); # first dept
my $sw = Tree::DAG_Node->new; # new dept
$org->add_daughter($sw); # add to root
$sw->name('Software'); # name it
$sw->new_daughter->name('MIS'); # add sub-depts
$sw->new_daughter->name('System Operations');
$org->new_daughter->name('Pipe line'); # one more dept
print map "$_\n", @{$org->draw_ascii_tree},"\n";
print $org->dump_names;
__END__
output:
|
<Office of President>
/-------------------+------------------\
| | |
<Recruiting> <Software> <Pipe line>
/------------\
| |
<MIS> <System Operations>
'Office of President'
'Recruiting'
'Software'
'MIS'
'System Operations'
'Pipe line'
You can also build a tree on the fly, from an existing list of lists. Notice that in this case the root is at the bottom (as in botanical trees ;-) )
my $tree =
[
[ 'Recruiting' ],
[
[ 'MIS' ], [ 'System Operations' ],
'Software'
],
[ 'Pipe line' ],
'Office of President'
];
my $org = Tree::DAG_Node->lol_to_tree($tree);
For more examples, see Introduction to Tree::DAG_Node in Tutorials.
Update Added code comments.
_ _ _ _
(_|| | |(_|><
_|
| [reply] [d/l] [select] |
Re: Logic for sorting of this given array
by broquaint (Abbot) on Aug 28, 2003 at 10:05 UTC
|
Or you could have an actual nested tree e.g
my %tree = (
"Office of President" => {
Recruiting => undef,
'Pipe line' => undef,
Software => {
MIS => undef,
'System Operations' => undef,
},
}
);
print dump_tree(\%tree);
sub dump_tree {
my($tree, $indent) = ( $_[0], $_[1] || 0 );
my $ret = '';
for(sort keys %$tree) {
$ret .= " " x $indent."$_\n";
$ret .= dump_tree($tree->{$_}, $indent + 2)
if ref $tree->{$_} and ref $tree->{$_} eq 'HASH';
}
return $ret;
}
__output__
Office of President
Pipe line
Recruiting
Software
MIS
System Operations
Which, as you can see, lends itself to a nice recursive subroutine to dump the given tree.
HTH
_________ broquaint
update: changed code to better reflect the desired data structure | [reply] [d/l] |
Re: Logic for sorting of this given array
by CombatSquirrel (Hermit) on Aug 28, 2003 at 10:36 UTC
|
I suppose Zaxo's code won't work for you, because you used the array to describe a nested structure with sub-departments and such. In general, if you describe nested structures, use nested structures.
Have a look at the following code; I think it should solve your problem:
#!perl
use strict;
use warnings;
sub returnParsed {
my ($array, $index, $level) = @_;
my $levelhash = {};
while ($index < @$array) {
last if ($array->[$index]->{'level'} < $level);
if ($array->[$index]->{'level'} == $level) {
$levelhash->{$array->[$index]->{'department'}}
= returnParsed($array, $index + 1, $level + 1);
}
++$index;
}
return $levelhash;
}
sub dumpSorted {
my ($structure, $indent, $startindent) = @_;
my $dumped = '';
for (sort keys %$structure) {
$dumped .= " " x $startindent . "$_\n";
$dumped .= dumpSorted($structure->{$_}, $indent, $startindent +
+$indent);
}
return $dumped;
}
my @array = ({ level => 1, department => 'Office of President', },
{ level => 2, department => 'Recruiting', },
{ level => 2, department => 'Software', },
{ level => 3, department => 'MIS', },
{ level => 3, department => 'System Operations', },
{ level => 2, department => 'Pipe line', },
);
print dumpSorted(returnParsed(\@array, 0, 1), 3, 3);
Hope this helped.
CombatSquirrel.
Entropy is the tendency of everything going to hell. | [reply] [d/l] |
|
THanks for the help, it is usefull. But i have another problem that i need to pass more parameters in my array along with the level and department. it could be more than 3-4 now my array is like this :
my @array = ({ level => 1,department => 'Office of President', linkdetails = "something"},
{ level => 2, department => 'Recruiting',linkdetails = "something1" },
{ level => 2, department => 'Software',linkdetails="something2"}, etc.....
how will i pass all these information along with the department ?. Actually i want to make on resultant array of hashes that will contain all the values so that i can pass to HTML template abd can print there. So level is also needed so that while printing in HTML page i can multiply the level into number of spaces.
my resultant array of hashes after sorting look like this :
my @array = ({ level => 1, department => 'Office of President',},
{ level => 2, department => 'Pipe line',link="",},
{ level => 2, department => 'Recruiting',link=""},
{ level => 2, department => 'software',link="" },
{ level => 3, department => 'MIS',link="" },
{ level => 3, department => 'System Operations',link="" },
);
need ur help in this ...
Thanks
| [reply] |
|
Some pieces of advice:
- Enclose array definitions, etc. in <code>-blocks
- It's not link="", but link => "", or you'll get a syntax error
- Capitalisation increases legibility ;-)
To the code:
#!perl
use strict;
use warnings;
use Data::Dumper;
sub returnParsedRec {
my ($array, $index, $level) = @_;
my $levelhash = {};
my $otherfields;
while ($index < @$array) {
last if ($array->[$index]->{'level'} < $level);
if ($array->[$index]->{'level'} == $level) {
$otherfields = {};
for (keys %{$array->[$index]}) {
$otherfields->{$_} = $array->[$index]->{$_}
unless ($_ eq 'level' or $_ eq 'department');
}
$levelhash->{$array->[$index]->{'department'}}
= [ $otherfields, returnParsedRec($array, $index + 1, $lev
+el + 1) ];
}
++$index;
}
return $levelhash;
}
sub unParseRec {
my ($levelhash, $result, $level) = @_;
my $tmphash;
for (sort keys %$levelhash) {
$tmphash = $levelhash->{$_}->[0];
$tmphash->{'department'} = $_;
$tmphash->{'level'} = $level;
push @$result, $tmphash;
unParseRec($levelhash->{$_}->[1], $result, $level + 1);
}
return $result;
}
sub returnParsed {
return returnParsedRec(shift, 0, 1);
}
sub unParse {
unParseRec(shift, [], 1);
}
my @array = (
{ level => 1,department => 'Office of President', linkdetails => "some
+thing"},
{ level => 2, department => 'Recruiting',linkdetails => "something1" }
+,
{ level => 2, department => 'Software', linkdetails => "something2"},)
+;
my $struct = returnParsed(\@array);
print Dumper($struct);
#print Dumper \@array;
print "\n" . "=" x 70 . "\n\n";
print Dumper(unParse($struct));
Be aware that HTML should not be formatted with spaces, look for lists (<ul>, <ol>, <dl>) and tables.
Hope this helped.
CombatSquirrel.
Entropy is the tendency of everything going to hell. | [reply] [d/l] [select] |
|
|