The question has already been answered and accepted, but I have to open my trap anyway...
First, I think your structure is off. It should look like this:
$VAR1 = {
'123' => bless( {
'ARRAY' => [
bless( {
'PRODUCT' => 'Dell',
'TYPE' => '210'
}, 'Product' ),
bless( {
'PRODUCT' => 'Dell',
'TYPE' => 'TZ-200'
}, 'Product' ),
bless( {
'PRODUCT' => 'Dell',
'TYPE' => 'TZ-200'
}, 'Product' )
]
}, 'Build' ),
'abc' => bless( {
'ARRAY' => [
bless( {
'PRODUCT' => 'Dell',
'TYPE' => 'Powerconnect-5600'
}, 'Product' ),
bless( {
'PRODUCT' => 'Dell',
'TYPE' => 'R-720'
}, 'Product' ),
bless( {
'PRODUCT' => 'Dell',
'TYPE' => 'R-920'
}, 'Product' )
]
}, 'Build' )
};
I base this on the output you want. It looks like you have Builds that consist of a list of products. The products consist of a Product Type and the Product Description. In your original structure you have:
`456` => Workset`
But this part of the structure makes no sense, and you don't use it. Maybe you meant this to be the Branch Type? It's hard to say. Let everything else I don't understand, I ignored it.
Now, how should you parse this structure? You should use Perl Object Oriented Programming. This allows you to stop worrying about your data structure. Your class definitions will take care of that. You don't have to worry if this was an array of hashes, or a hash or arrays, or maybe an array or arrays, of hashes.
Here's the entire main program. Two loops: In the first loop, I read in the data (consisting of three tab separated items: The Build Number, Prodtype, and Product). It's clear, short, and easy to understand. It takes just six lines of code to parse through your entire data structure:
use strict;
use warnings;
use feature qw(say);
my %workset;
my $prev_build;
#
# Read in the Data
#
while ( my $line = <DATA> ) {
chomp $line;
my ($build_num, $prodtype, $description) = split /\t/, $line;
my $product = Product->new( $prodtype, $description );
if ( not $prev_build or $prev_build ne $build_num ) {
$workset{$build_num} = Build->new;
$prev_build = $build_num;
}
$workset{$build_num}->Push($product);
}
#
# Parse the structure and Print it out
#
for my $workset ( sort keys %workset ) {
say "Build Number: " . $workset;
while ( my $product = $workset{$workset}->Pop ) {
say "Product: " . $product->Product . " Prodtype: " . $product->Type;
}
}
And here's the output:
Build Number: 123
Product: Dell Prodtype: TZ-200
Product: Dell Prodtype: TZ-200
Product: Dell Prodtype: 210
Build Number: abc
Product: Dell Prodtype: R-920
Product: Dell Prodtype: R-720
Product: Dell Prodtype: Powerconnect-5600
Just like you wanted.
The rest of my program is the class definitions. Most of the time, I simply append the definitions to the end of my main program because I never use them again. Still, using object oriented code makes programming faster and easier.
And here's the rest of my program:
package Product;
sub new {
my $class = shift;
my $product = shift;
my $type = shift;
my $self = {};
bless $self, $class;
$self->Product($product);
$self->Type($type);
return $self;
}
sub Product {
my $self = shift;
my $product = shift;
if ( defined $product ) {
$self->{PRODUCT} = $product;
}
return $self->{PRODUCT};
}
sub Type {
my $self = shift;
my $type = shift;
if ( defined $type ) {
$self->{TYPE} = $type;
}
return $self->{TYPE};
}
package Build;
use Carp;
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
return $self;
}
# PRIVATE -- No peeking
sub _Array_ref {
my $self = shift;
if ( not exists $self->{ARRAY} ) {
$self->{ARRAY} = [];
}
return $self->{ARRAY};
}
sub Index {
my $self = shift;
my $index = shift;
if ( not defined $self->{INDEX} ) {
$self->{INDEX} = 0;
}
if ( defined $index ) {
$self->{INDEX} = $index;
}
if ( $self->{INDEX} < 0 or $self->{INDEX} > $self->Size ) {
croak qq(Index out of range: Set to "$index");
}
return $self->{INDEX};
}
sub Array {
my $self = shift;
my @array = @{ $self->_Array_ref };
return wantarray ? @array : \@array;
}
sub Size {
my $self = shift;
my $array_ref = $self->_Array_ref;
return $#{ $array_ref };
}
sub Push {
my $self = shift;
my $product = shift;
if ( not defined $product or not $product->isa("Product") ) {
croak qq(Push Method for requires a Product Class to push);
}
my $array_ref = $self->_Array_ref;
push @{ $array_ref }, $product;
return $#{ $array_ref };
}
sub Pop {
my $self = shift;
my $array_ref = $self->_Array_ref;
return pop @{ $array_ref };
}
sub Next {
my $self = shift;
my $index = $self->Index;
my $array_ref = $self->_Array_ref;
$index += 1;
$self->Index($index);
return ${ $array_ref }[$index];
}
sub Prev {
my $self = shift;
my $index = $self->Index;
my $array_ref = $self->_Array_ref;
$index -= 1;
$self->Index($index);
return ${ $array_ref }[$index];
}
package main;
__DATA__
abc Dell Powerconnect-5600
abc Dell R-720
abc Dell R-920
123 Dell 210
123 Dell TZ-200
123 Dell TZ-200