Simplify hash structure

Hi all,
I need to modify the hash structure given below:
$hash_value = { '75.34.42.17561630730' => { '2005' => [ '11.5', '147,296' ], '2004' => [ '9.2', '132,116' ], '2002' => [ '7.6', '114,837' ], '2000' => [ '', '100,000' ], '2006' => [ '9.4', '161,184' ], '2001' => [ '6.7', '106,733' ], '2003' => [ '5.4', '120,988' ] },
'75.34.42.17510225758' => { '2004' => [ '', '618,000' ], '2002' => [ '7.6', '709,694' ], '2001' => [ '6.7', '659,608' ] } };

The outer hash key for the $hash_value  is '75.34.42.17561630730' and '75.34.42.17510225758' .
which points to set of keys called year (2005 ,2004 etc) and which point to array.

I would like to get the above hash in the form as
$hash_new_before_sort = { '2005' => [ '11.5', '147,296' ,'',''], '2004' => [ '9.2', '132,116' ,'', '618,000' ], '2002' => [ '7.6', '114,837','7.6', '709,694' ], '2000' => [ '', '100,000' ,'',''], '2006' => [ '9.4', '161,184' ,'',''], '2001' => [ '6.7', '106,733' ,'6.7', '659,608' ], '2003' => [ '5.4', '120,988','','' ]}

that's 2nd record set will be added to the 1st set -  (  '75.34.42.17561630730' is the 1st record set and  '75.34.42.17510225758'  2nd record set). If year not present in the 2nd set ,null values ('') will be added to the year array.

and sort keys by ascending
$hash_new_after_sort = { '2000' => [ '', '100,000' ,'',''],  '2001' => [ '6.7', '106,733' ,'6.7', '659,608' ], '2002' => [ '7.6', '114,837','7.6', '709,694' ], '2003' => [ '5.4', '120,988','','' ],'2004' => [ '9.2', '132,116' ,'', '618,000' ], '2005' => [ '11.5', '147,296' ,'',''], '2006' => [ '9.4', '161,184' ,'','']}

Thanks

r_karAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Adam314Commented:
The order you enter data into the hash is irrelevant.  If you need to process things in a sorted order, you sort it when you are using it, not when you enter it.

use Data::Dumper;

my $hash_value = {
  '75.34.42.17561630730' => {
    '2005' => [ '11.5', '147,296' ],
    '2004' => [ '9.2', '132,116' ],
    '2002' => [ '7.6', '114,837' ],
    '2000' => [ '', '100,000' ],
    '2006' => [ '9.4', '161,184' ],
    '2001' => [ '6.7', '106,733' ],
    '2003' => [ '5.4', '120,988' ] },
  '75.34.42.17510225758' => {
    '2004' => [ '', '618,000' ],
    '2002' => [ '7.6', '709,694' ],
    '2001' => [ '6.7', '659,608' ] } };


#Get all keys for main hash
my @mainkeys=keys %$hash_value;

#Get all years
my %years;
foreach my $mainkey (keys %$hash_value) {
      foreach my $year (keys %{ $hash_value->{$mainkey} } ) {
            $years{$year}=1;
      }
}

my $new_hash;
foreach my $mainkey (keys %$hash_value) {
      foreach my $year (keys %years) {
            if(!exists($hash_value->{$mainkey}->{$year})){
                  #Add empty string if year doesn't exist
                  push @{ $new_hash->{$year} }, '';
                  next;
            }
            push @{ $new_hash->{$year} }, $_ foreach ( @{ $hash_value->{$mainkey}->{$year} } );
      }
}

print Dumper($new_hash);
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ozoCommented:
use Data::Dumper;
$hash_value = { '75.34.42.17561630730' => { '2005' => [ '11.5', '147,296' ], '2004' => [ '9.2', '132,116' ], '2002' => [ '7.6', '114,837' ], '2000' => [ '', '100,000' ], '2006' => [ '9.4', '161,184' ], '2001' => [ '6.7', '106,733' ], '2003' => [ '5.4', '120,988' ] },
'75.34.42.17510225758' => { '2004' => [ '', '618,000' ], '2002' => [ '7.6', '709,694' ], '2001' => [ '6.7', '659,608' ] } };
my $i;
for( '75.34.42.17561630730', '75.34.42.17510225758' ){
  while( my($k,$v) = each %{$hash_value->{$_}} ){
     @{$hash_new_before_sort->{$k}}[$i,$i+1] = @$v;
  }
  $i += 2;
}
print Dumper $hash_new_before_sort;
# hashes are an unordered data structure, so it doesn't make sense to takl about sorting it
# you can sort a lis of keys and do something with that
$"=", ";
for( sort keys %$hash_new_before_sort ){
   print "$_ => [@{$hash_new_before_sort->{$_}}]\n";
}
# or you could use a module that implements Perl hashes that preserve the order
use Tie::IxHash;
$t = tie(%hash_new_after_sort, Tie::IxHash);
for( sort keys %$hash_new_before_sort ){
    $hash_new_after_sort{$_} = $hash_new_before_sort->{$_};
}
0
r_karAuthor Commented:
Hi Adam314,ozo
Thanks a lot for your help.
The blow structure (now it contains 4 records) I used to test the code. There is some problem in output.

my $hash_value = { '75.34.42.17534849371' => { '2005' => [ '11.5', '257,768' ], '2004' => [ '9.2', '231,202' ], '2001' => [ '6.7', '186,782' ], '1998' => [ '', '175,000' ], '2002' => [ '7.6', '200,965' ], '2006' => [ '9.4', '282,072' ], '2000' => [ '7.7', '175,000' ], '2003' => [ '5.4', '211,728' ], '1999' => [ '-42.4', '162,436' ] },
'75.34.42.17561630730' => { '2005' => [ '11.5', '147,296' ], '2004' => [ '9.2', '132,116' ], '2002' => [ '7.6', '114,837' ], '2000' => [ '', '100,000' ], '2006' => [ '9.4', '161,184' ], '2001' => [ '6.7', '106,733' ], '2003' => [ '5.4', '120,988' ] },
'75.34.42.17511726663' => { '2005' => [ '11.5', '294,592' ], '1995' => [ '', '200,000' ], '2004' => [ '9.2', '264,231' ], '2001' => [ '6.7', '213,465' ], '2002' => [ '7.6', '229,675' ], '2006' => [ '9.4', '322,368' ], '2000' => [ '7.7', '200,000' ], '2003' => [ '5.4', '241,975' ], '1999' => [ '-42.4', '185,641' ] },
'75.34.42.17510225758' => { '2004' => [ '', '618,000' ], '2002' => [ '7.6', '709,694' ], '2001' => [ '6.7', '659,608' ] } };

adam314,
provided code is excellent. I have added '' in push @{ $new_hash->{$year} }, '',''; to maintain the structure.
The problem which I noticed, I won't be able to distinguish the array values that belongs to outer key )say '75.34.42.17534849371'  etc). The above structure contains 4 outer keys ('75.34.42.17534849371','75.34.42.17561630730', '75.34.42.17561630730','75.34.42.17511726663','75.34.42.17510225758'). So we can say first 2 data in the array belongs to '75.34.42.17534849371' and next 2 data belongs to '75.34.42.17561630730' etc. But in ozo's code I can distinguish (there is some problem with some year data).
Could you please help me to resolve those issue?

ozo,
different approach and its excellent. I got lots of ideas from you and adam314.
There is some problem in year 2000, Actually we need to display
2000 => [ 7.7, 175,000, , 100,000, 7.7,  200,000, , , ]
But from present output, its displaying
2000 => [ 7.7, 175,000, , 100,000,  , 100,000,  7.7,  200,000 ] # additional value ( , 100,000) can be seen

same thing happend in 2006 also.

Could you please resolve this?

Thanks
0
ozoCommented:
I think , 100,000, is appearing twice because
75.34.42.17561630730 is listed twice in your list
('75.34.42.17534849371','75.34.42.17561630730', '75.34.42.17561630730','75.34.42.17511726663','75.34.42.17510225758')
If the purpose of having 75.34.42.17561630730 twice was not to have , 100,000, twice, then how did you get 7.7, 175,000, , 100,000, 7.7,  200,000, , , ]?

Will the first outer key listed always contain all the inner keys that will be found within subsequent inner keys?
0
r_karAuthor Commented:
Hi Adam314, ozo,

I have modified the script as per my requirement. Thanks  a lot for your help.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Perl

From novice to tech pro — start learning today.