1

I have below input

XXI3|XI39|MP0@1
XXI3|XI39|MP0@2
XXI3|XI39|MP0@3
XXI3|XI39|MP0@4
XXI3|XI39|MP0@5

Can someone help to get below output ...

$myhash{'XXI3'}{'XI39'}{'MP0'} => (1,2,3,4,5)

I tried to create a nested hash using string concat and eval functions and am just not getting how to form array in value of nested hash.

0

2 Answers 2

3

Fairly general solution:

my $input = 'XXI3|XI39|MP0@1 XXI3|XI39|MP0@2 XXI3|XI39|MP0@3 XXI3|XI39|MP0@4 XXI3|XI39|MP0@5';
my %hash; # output

for my $word (split " ", $input) {
  my ($path, $value) = split /\@/, $word, 2;
  my @path = split /\|/, $path;
  my $last = pop @path;

  my $target = \%hash;
  for my $path_elem (@path) {
    $target = ($target->{$path_elem} ||= {});
  }
  push @{ $target->{$last} }, $value;
}

First, break up the input into words, and process one word at a time.

Then separate the "path" and "value" portions of the word by splitting on @. Split the path into its components on |. Remove the last component of the path and save it for later.

Take a reference to the top of the data structure, and for each component in the path (except for the last), go down one level, creating that level as an empty hash if it doesn't already exist.

For the last path component, push onto an array reference (which will be created by autovivification if necessary).

Result:

{
  'XXI3' => {
              'XI39' => {
                          'MP0' => [
                                     '1',
                                     '2',
                                     '3',
                                     '4',
                                     '5'
                                   ]
                        }
            }
};
Sign up to request clarification or add additional context in comments.

3 Comments

my $last = pop @path; my $target = \%hash; for my $path_elem (@path) { $target = ($target->{$path_elem} ||= {}); } push @{ $target->{$last} }, $value; simplifies to my $p = \\%hash; $p = \( $$p->{$path_elem} ) for @path; push @$$p, $value;
Yeah, I suppose :)
one of the most common (though still uncommon) uses of scalar references :)
3
use Data::Diver 'DiveRef';

my %myhash;
for my $line (<$filehandle>) {
    chomp $line;
    my ($keys, $value) = split /\@/, $line;
    my @keys = split /\|/, $keys;
    push @${ DiveRef(\%myhash, \(@keys)) }, $value
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.