combining data structures

Guys, I need help on writing a code that will do the following:

1. identify the values of a reference to HoH that are different from a given Hash
Hash -->
my %Line = ('LIST'=>'2','PAGES'=>'77','EDITION'=>'new');

HoH-->
 my $HoH = { 'BOOK1' => {'LIST'=>'2','PAGES'=>'100','EDITION'=>'old'},
'BOOK2' => {'LIST'=>'10','PAGES'=>'77','EDITION'=>'new'},
'BOOK3' => {'LIST'=>'20','PAGES'=>'30','EDITION'=>'old'},
'BOOK4' => {'LIST'=>'2','PAGES'=>'300','EDITION'=>'new'}};

2. create a HoH that will contain these elements
desired output:
  my $HoH = { 'BOOK1' => {'PAGES'=>'100','EDITION'=>'old'},
                       'BOOK2' => {'LIST'=>'10'},
                       'BOOK3' => {'LIST'=>'20','PAGES'=>'30','EDITION'=>'old'},
                       'BOOK4' => {'PAGES'=>'300'}};

3. print with the following format:
1. BOOK1 (PAGES:100, EDITION:old)                                   2. BOOK2 (LIST:10)
3. BOOK3 (LIST:20, PAGES:30, EDITION:old)                       4. BOOK4 (PAGES:300)

I'd greatly appreciate it someone could help me out with this. Thanks in advance!!!!
cucugirlAsked:
Who is Participating?
 
Adam314Connect With a Mentor Commented:
Wasn't sure if you wanted to change your original $HoH, or make a new.  This first makes a copy of $HoH to $HoH2, then changes that.  If you want to change your original $HoH, just replace $HoH2 with $HoH, and remove the dclone line.
use Storable 'dclone';
 
my %Line = ('LIST'=>'2','PAGES'=>'77','EDITION'=>'new');
 
my $HoH = {'BOOK1' => {'LIST'=>'2','PAGES'=>'100','EDITION'=>'old'},
           'BOOK2' => {'LIST'=>'10','PAGES'=>'77','EDITION'=>'new'},
           'BOOK3' => {'LIST'=>'20','PAGES'=>'30','EDITION'=>'old'},
           'BOOK4' => {'LIST'=>'2','PAGES'=>'300','EDITION'=>'new'}};
 
##### This line makes a copy of $HoH
my $HoH2=dclone($HoH);
 
##### This removes key/value pairs from $HoH2
foreach my $book (keys %$HoH2) {
	foreach my $key (keys %{$HoH2->{$book}}) {
		next if $HoH2->{$book}->{$key} ne $Line{$key};
		delete $HoH2->{$book}->{$key};
	}
}
 
##### This displays them
my $count=0;
foreach my $book (sort keys %$HoH2) {
	$count++;
	printf '%-50s', "$book (" . join(", ", map {"$_:$HoH2->{$book}->{$_}"} keys %{$HoH2->{$book}}) . ")";
	print "\n" unless ($count % 2);
}

Open in new window

0
 
cucugirlAuthor Commented:
Adam, now that I just notice the possibility of $HoH2 being empty is there a way to print this:

book1

rather than:

book1()

thanksssss for all your help! :)
0
 
Adam314Commented:

##### This displays them
my $count=0;
foreach my $book (sort keys %$HoH2) {
    $count++;
    my $attr=join(", ", map {"$_:$HoH2->{$book}->{$_}"} keys %{$HoH2->{$book}});
    printf '%-50s', "$book" . ($attr ? " ($attr)" : "");
    print "\n" unless ($count % 2);
}

Open in new window

0
Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
cucugirlAuthor Commented:
question... I don't have dclone, use storage in my PERL version, is there another way to copy this hash so that the original one is not affected? thanks!
0
 
ozoCommented:
#if $HoH is known to be exactly 2 deep, you might do

my $HoH2={map{$_=>{%$HoH->{$_}}}keys %$HoH};
0
 
ozoCommented:
#or in one step

my $HoH2={
      map{
        my$book=$HoH->{$_};
        $_=>{
            map{
                $_ => $book->{$_}
            }
            grep{
                $book->{$_} ne $Line{$_}
            }
            keys %$book
        }
      }keys %$HoH
    };
0
 
cucugirlAuthor Commented:
thanks ozo! question... I'd like to use $_ as least as possible... how can reduce the amount of $_ in that loop? thanks!!
0
 
ozoCommented:
my $HoH2={
      map{
          my $book=$_;
          my $hash=$HoH->{$book};
          my %new=();
          for $key ( keys%$hash ){
              $new{$key}=$hash->{$key} if  $hash->{$key} ne $Line{$key}
          }
          $book=>{%new}
       }keys %$HoH
    };
0
 
ozoCommented:
my $HoH2;
while( my($book,$hash) = each %$HoH  ){
          my %new=();
          for my $key ( keys%$hash ){
              $new{$key}=$hash->{$key} if  $hash->{$key} ne $Line{$key}
          }
          $HoH{$book} = {%new};
};
0
 
cucugirlAuthor Commented:
ok got it! thankssss! question.. why would copying it directly affect the original one in this case? if I have the following
@array2 = [1,2,3];
@array1 = @array2;
and do something to @array1 nothing will happen to @array2.. but why in this case do I have to copy it like this? I want to make sure I understand why the original element is being affected with this code..

thanks!
0
 
ozoCommented:
did you mean
@array2 = (1,2,3);
?

@array2 = [1,2,3];
would mean that @array2 has a single element with $array2[0] being a reference to a list of 3 elements.
If you meant that, it would have been better to write it as
@array2 = ([1,2,3]);
or
$array2[0] = [1,2,3];
0
 
cucugirlAuthor Commented:
ozo thanks for your help! :)

##### This displays them
my $count=0;
foreach my $book (sort keys %$HoH2) {
      $count++;
      printf '%-50s', "$book (" . join(", ", map {"$_:$HoH2->{$book}->{$_}"} keys %{$HoH2->{$book}}) . ")";
      print "\n" unless ($count % 2);
}

this piece of code will display both columns:
1. BOOK1 (PAGES:100, EDITION:old)                                   2. BOOK2 (LIST:10)
3. BOOK3 (LIST:20, PAGES:30, EDITION:old)                       4. BOOK4 (PAGES:300)

is it possible to just add one line in this code to make it smart enough to do the following:
1. BOOK1 (PAGES:100, EDITION:old)                                   2. BOOK2 (LIST:10)
3. BOOK3 (LIST:20, PAGES:30, EDITION:old, PAGES:100, YEAR:1990)
4. BOOK4 (PAGES:300)

if the content inside of the parenthesis, then just print the next element in another line? thanks in advance for the help!

0
 
cucugirlAuthor Commented:
if the content inside of the parenthesis is too much, then just print the next element in another line? thanks in advance for the help!
0
 
ozoCommented:
my $content =  printf '%-50s', "$book (" . join(", ", map {"$_:$HoH2->{$book}->{$_}"} keys %{$HoH2->{$book}}) . ")";
$count = 0 if length $content > 50;
print $content;
print "\n" unless ($count % 2);

#that should probably be a different question, since it's not really germane to the original question
0
 
ozoCommented:
#sorry
my $content =  sprintf '%-50s', "$book (" . join(", ", map {"$_:$HoH2->{$book}->{$_}"} keys %{$HoH2->{$book}}) . ")";
0
 
cucugirlAuthor Commented:
##### This displays them
my $count=0;
foreach my $book (sort keys %$HoH2) {
    $count++;
    my $attr=join(", ", map {"$_:$HoH2->{$book}->{$_}"} keys %{$HoH2->{$book}});
    printf '%-50s', "$book" . ($attr ? " ($attr)" : "");
    print "\n" unless ($count % 2);
}

my $attr=join(", ", map {"$_:$HoH2->{$book}->{$_}"} keys %{$HoH2->{$book}});
one last question.. in this line: how can I only print the value? rather than the key:value? thanks!
0
 
cucugirlAuthor Commented:
also ozo.. in this snippet what do you mean by $line{$new}?

my $HoH2;
while( my($book,$hash) = each %$HoH  ){
          my %new=();
          for my $key ( keys%$hash ){
              $new{$key}=$hash->{$key} if  $hash->{$key} ne $Line{$key}
          }
          $HoH{$book} = {%new};
};
0
 
ozoCommented:
my $attr=join(", ",  keys %{$HoH2->{$book}});

where do you see $line{$new}?
0
 
cucugirlAuthor Commented:
             $new{$key}=$hash->{$key} if  $hash->{$key} ne $Line{$key}
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.