comparing a 2 hash of hashes

P

perl_newbie

My problem is that I would like to compare 2 hash of hashes. I got a
gold standard; which is my hierarchy, and a list of cells in the cad
tree that were copied with erroneous cell names that I would like to
clean up. The program below works for a $cadcell name but not library
and I would like it to be more robust. I like to compare the $hie_cell
in my gold standard exists in my cad tree and the library associated
with my $hie_cell->$hie_lib in the gold standard is also the same in my
cad tree cadcell->$cadlib. Then anything that is not found in the gold
standard is then push to a file.
here in my last sub routine, I need to have additional checks for the
library too and not the cell name alone but need help and any help will
be very much appreciated.

sub comp_2_cell_list
{
foreach(<L2>)
{
if(~/^\s?(\S+)\s+(\S+)/)
{
my ($cadlib,$cadcell)=($1,$2);
#$cadrec->{$cadcell}->{$cadlib}=1;

#here I need to check for libraries too!

if(! exists($hierec->{$cadcell}))
{
print "list to dump: $cadcell\n";
print BCELL "$cadcell\n";
}
}
}
}


input files below:

Gold standard
Lib0 cell1
Lib1 cell2
Lib3 cell3
Lib4 cell1 --note this would be a warning(my comment)
Lib1 cell4

Cad tree hierarchy
Lib0 cell1
Lib1 cell2
Lib1 cell2A --note is junk; bad name; to be push to a file
Lib3 cell3
Lib4 cell3 --note this is also junk; copied in the wrong lib
Lib4 cell1
Lib1 cell4

My code only flags the cells that are not found with in the hierarchy
but I also need to check the libraries associated with the $hiecell.
Can you help?

-------my code---------------------------------
#!usr/bin/perl -w

use strict;

# use Getopt::Long;

my $show_file={};
my $hierec={};
my $cadrec={};
my $hie_cell={};
my $hie_lib={};
my $cadcell={};
my $cadlib={};
my @cell=();

#-------------------------------------------------------------
#getting the arguments of the files to be read by checker
if ($#ARGV != 1 )
{
print "Requires these 2 files <showhi> <compr_list>\n";
exit;
}

my $list1=$ARGV[0];
my $list2=$ARGV[1];

open(L1,"<$list1") || die "cannot open first file";
open(L2,"<$list2") || die "cannot open second file";


#----------------------------------------------------
#opening files for write in user's dir

my $dir = `pwd`;
chop($dir);

my $efile = $dir."/rec.err";
open(ERR ,">$efile") || die "cannot open new error file\n";

my $gfile = $dir."/rec.gd_cll";
open(GCELL,">$gfile") || die "cannot open the Good Cell file\n";

my $dfile = $dir."/rec.dmp";
open(BCELL,">$dfile") || die "cannot open Bad Cell file\n";


###########################
# let's find the bad cells#
###########################

#-------------------------------------------------------
#assigning the items of interest in a hash
# hash key key
# rec -> cell -> lib

while(<L1>)
{
$show_file=$_;

if ($show_file=~/^\S+\s+\d\.\s+(\S+)\s+(\S+)/ ||
$show_file=~/^\d\.\s+(\S+)\s+(\S+)/)
{
my ( $hie_cell, $hie_lib)= ($2, $1);
$hierec->{$hie_cell}->{$hie_lib}=1;
#making the cell & lib to exist as a hash later to be used as error
finder
}
}

#-----------------------------------------------
# place the lib keys in an array variable for easier readability,

#&error_check;

sub error_check
{
foreach my $hie_cell (keys %$hierec)
{
my @lib = sort keys %{ $hierec->{ $hie_cell } };
if (@lib == 1)
{
print "$hie_cell \t(@lib)\n";
print GCELL"$hie_cell (@lib)\n";
}
if( @lib >1 )
{
print ERR "$hie_cell (@lib) - Warning/Error?\n";
}
}

}
#-------------------------------------------------
# only the cells is being checked but need the
# library to be checked too.

&comp_2_cell_list;
sub comp_2_cell_list
{
foreach(<L2>)
{
if(~/^\s?(\S+)\s+(\S+)/)
{
my ($cadlib,$cadcell)=($1,$2);
#$cadrec->{$cadcell}->{$cadlib}=1;
if(! exists($hierec->{$cadcell}))
{
print "list to dump: $cadcell\n";
print BCELL "$cadcell\n";
}
}
}
}
#-------------------------------------------------------------------------------

close(GCELL);
close(BCELL);
close(ERR);
 
G

Greg Bacon

: My problem is that I would like to compare 2 hash of hashes. I got a
: gold standard; which is my hierarchy, and a list of cells in the cad
: tree that were copied with erroneous cell names that I would like to
: clean up. [...]

The regular expressions in your program don't match your sample
inputs.

If I understand your problem, you may have overcomplicated your
data structure. From your description, it seems that each cell has
only one library. If so, you can use a simple hash:

$ cat gold-standard.txt
Lib0 cell1
Lib1 cell2
Lib3 cell3
Lib4 cell1
Lib1 cell4

$ cat cad-tree.txt
Lib0 cell1
Lib1 cell2
Lib1 cell2A
Lib3 cell3
Lib4 cell3
Lib4 cell1
Lib1 cell4

$ cat try
#! /usr/local/bin/perl

use warnings;
use strict;

sub lib_hierarchy {
my $path = shift;

open my $fh, $path or die "$0: open $path: $!";

my %lib;

while (<$fh>) {
my($lib,$cell) = split;

next unless defined($lib) && defined($cell);

if ($lib{$cell}) {
warn "$0: $path:$.: multiple libraries for cell '$cell'\n";
next;
}

$lib{$cell} = $lib;
}

\%lib;
}

## main
die "Usage: $0 showhi compr-list\n" unless @ARGV == 2;

my($showhi,$compr) = @ARGV;

my $goldlib = lib_hierarchy $showhi;

open my $fh, $compr or die "$0: open $compr: $!";

while (<$fh>) {
my($lib,$cell) = split;

next unless defined($lib) && defined($cell);

unless (exists $goldlib->{$cell}) {
warn "$0: $compr:$.: no such cell '$cell'\n";
next;
}

unless ($goldlib->{$cell} eq $lib) {
warn "$0: $compr:$.: mismatch in cell '$cell':\n" .
" want '$goldlib->{$cell}\n" .
" got '$lib'\n";
}
}

$ ./try gold-standard.txt cad-tree.txt
./try: gold-standard.txt:4: multiple libraries for cell 'cell1'
./try: cad-tree.txt:3: no such cell 'cell2A'
./try: cad-tree.txt:5: mismatch in cell 'cell3':
want 'Lib3
got 'Lib4'
./try: cad-tree.txt:6: mismatch in cell 'cell1':
want 'Lib0
got 'Lib4'

You didn't mention that you expect a warning for cell1, so I'm concerned
that I misunderstood why you expected the warnings.

Hope this helps,
Greg
 
P

perl_newbie

my heirarchy input files have some junk in front, in some instances and
i am just retriving the items of interest.
the reason that I set the hiercell and hierlib as keys it was that I
needed this to be unique, even in my gold standard but it was the only
way I knew how. I did not wish to overcomplicate the data structure.

the warning is on cell1 is expected since it is found in another
library in a different library other than the one in the gold standard.
 
P

perl_newbie

I got a problem with the syntax with exists argument. I wish to only
referece the hash hierec->key->lib to check if the $cad lib exists in 2
list but perl complains that it is not a hash element :"exists operator
argument is not a HASH element"

can you point out to me what the right syntax is, why can I use the
string in the hash and compare it to another string that is not in a
hash?


sub comp_2_cell_list
{
foreach(<L2>)
{
if(~/^\s?(\S+)\s+(\S+)/)
{

my ($cadlib,$cadcell)=($1,$2);
if(! exists($hierec->{$cadcell}))
{
print "list to dump: $cadcell\n";
print BCELL "$cadcell\n";
}


if(!exists($hierec->{$hier_cell} eq $cadlib))

I guess the error is here where my $cadlib is not a hash but I wish to
only reference the name of the $hier_lib to compare if these are the
same.

{
print "mismatch libs in:$cell
("$hierec{$hie_cell}","$cadlib")\n";
}
}
}
}
 
P

perl_newbie

I have attempted to fixed the previous error but I do not get the
desired output still. I suspect the $hierec->{$hie_cell} cannot be seen
in this block but I do not know why this wouldn't be seen.

Can you help me correct the code so that the $hie_lib can be tested
against the $cadlibs? I urgently need some help here to figure out how
to pass the values of the lib keys into this block to do comaparison.

--output:
mismatch libs in:HASH(0x40012e0c) (,lib3)
list to dump: cell2A
mismatch libs in:HASH(0x40012e0c) (,lib1)


--revised piece of code from my program

my ($cadlib,$cadcell)=($1,$2);
if(! exists($hierec->{$cadcell}))
{
print "list to dump: $cadcell\n";
print BCELL "$cadcell\n";
}

if($hierec->{$hie_cell} ne $cadlib)
this is the modification I'd done to attempt to fix the previous error.


{
print "mismatch libs in:$hierec ($hierec->{$cell},$cadlib)\n";
}
 
P

perl_newbie

I need help figuring out how to pass the keys of hash keys in the
subroutine below. I pasted the comple code and the problem areas where
I crash and burn. can you please point me out how to correct my
mistakes.

&comp_2_cell_list;
sub comp_2_cell_list
{
foreach(<L2>)
{
if(~/^\s?(\S+)\s+(\S+)/)
{

my ($cadlib,$cadcell)=($1,$2);
if(! exists($hierec->{$cadcell}))
{
print "list to dump: $cadcell\n";
print BCELL "$cadcell\n";
}

note, early in my program I set $her->{$cell}->{$lib}=1 for uniquiness.


my problem is that I cannot get the $hier->{$cell} which are my
libraries in the gold SNTD to reference with the $cadlib to see if it
exist. if it doesn't then I want them push to a different file to be
check later.
for my futre reference, I'd like to know how to fix the syntax in both
cases below.

1) # if(! exist(%{$hierec->{$cell}}->{$cadlib}))
error: Undefined subroutine &main::exist

2) if(%{$hierec} ne $cadlib)
empty hash, look at output

{
print "mismatch libs in:%{$hierec}
($hierec->{$cell},$cadlib)\n";
}
}
}
}




same input files as above, please refer to these:

Gold standard
Lib0 cell1
Lib1 cell2
Lib3 cell3
Lib4 cell1 --note this would be a warning(my comment)
Lib1 cell4


Cad tree hierarchy
Lib0 cell1
Lib1 cell2
Lib1 cell2A --note is junk; bad name; to be push to a file
Lib3 cell3
Lib4 cell3 --note this is also junk; copied in the wrong lib
Lib4 cell1 --note cell1 is in a different lib than gold stnd
Lib1 cell4


--output of error 1):
Undefined subroutine &main::exist
--output of error 2):
list to dump:cell1
mismatch libs in:%{HASH(0x40012e0c)} (,lib4)
list to dump: cell2A
mismatch libs in:HASH(0x40012e0c) (,lib1)

--code
#MAIN PERL SCRIPT
#!usr/bin/perl -w

use strict;

#use Getopt::Long; #for getting right arguments on the command line
#Data::Dumper;

my $show_file={};
my $hierec={};
my $cell={};
my $lib={};
my $cadcell={};
my $cadlib={};
my @cell=();
#------------------------------------------------------------------------
#getting the arguments of the files to be read by checker
#GetOptions("unsed_cell"=>\$moo{$oflag}
if ($#ARGV != 1 )
{
print "Requires these 2 files <showhi> <compr_list>\n";
exit;
}

my $list1=$ARGV[0];
my $list2=$ARGV[1];

open(L1,"<$list1") || die "cannot open first file";
open(L2,"<$list2") || die "cannot open second file";


#------------------------------------------------------------------------
#opening files for write in user's dir
my $dir = `pwd`;
chop($dir);

my $efile = $dir."/rec.err";
open(ERR ,">$efile") || die "cannot open new error file\n";

my $gfile = $dir."/rec.gd_cll";
open(GCELL,">$gfile") || die "cannot open the Good Cell file\n";

my $dfile = $dir."/rec.dmp";
open(BCELL,">$dfile") || die "cannot open Bad Cell file\n";


###########################
# let's find the bad cells#
###########################

#------------------------------------------------------------------------
#assigning the items of interest in a hash
# hash key key
# rec -> cell -> lib

while(<L1>)
{
$show_file=$_;

if ($show_file=~/^\S+\s+\d\.\s+(\S+)\s+(\S+)/ ||
$show_file=~/^\d\.\s+(\S+)\s+(\S+)/)
{
my ( $cell, $lib)= ($2, $1);
$hierec->{$cell}->{$lib}=1;
#making the cell & lib to exist as a hash later to be used as error
finder
}
}

#-------------------------------------------------------------------------------
# place the lib keys in an array variable for easier readability,

#&error_check;

sub error_check
{
foreach my $cell (keys %$hierec)
{
my @lib = sort keys %{ $hierec->{ $cell } };
if (@lib == 1)
{
print "$cell \t(@lib)\n";
print GCELL"$cell (@lib)\n";
}
if( @lib >1 )
{
print ERR "$cell (@lib) - Error?\n";
}
}

}
#@cell= keys %$hierec;
#print @cell;
#--------------------------------------------------------------------------------
print"#######################\n";
#&comp_2_cell_list;
sub comp_2_cell_list
{
foreach(<L2>)
{
if(~/^\s?(\S+)\s+(\S+)/)
{

my ($cadlib,$cadcell)=($1,$2);
if(! exists($hierec->{$cadcell}))
{
print "list to dump: $cadcell\n";
print BCELL "$cadcell\n";
}

# if(! exist(%{$hierec->{$cell}}->{$cadlib}))
this is where I need to find how to reference the $hierec->{$cell} ;
which are the $lib found in our gold stnd to compare against the
$cadlib.


# if(%{$hierec} ne $cadlib)

#try but i get some number instead of the string?

{
print "mismatch libs in:%{$hierec}
($hierec->{$cell},$cadlib)\n";
}
}
}
}
#-------------------------------------------------------------------------------

close(GCELL);
close(BCELL);
close(ERR);
 
P

perl_newbie

I apologize fro the incomple program above. The entire code is here and
disregard the code above that somehow got corrupted when I paste it.
please refer to the question, input files and output.


#MAIN PERL SCRIPT
#!usr/bin/perl -w

use strict;

#use Getopt::Long; #for getting right arguments on the command line
#Data::Dumper;

my $show_file={};
my $hierec={};
my $cell={};
my $lib={};
my $cadcell={};
my $cadlib={};
my @cell=();
#------------------------------------------------------------------------
#getting the arguments of the files to be read by checker
#GetOptions("unsed_cell"=>\$moo{$oflag}
if ($#ARGV != 1 )
{
print "Requires these 2 files <showhi> <compr_list>\n";
exit;
}

my $list1=$ARGV[0];
my $list2=$ARGV[1];

open(L1,"<$list1") || die "cannot open first file";
open(L2,"<$list2") || die "cannot open second file";


#------------------------------------------------------------------------
#opening files for write in user's dir
my $dir = `pwd`;
chop($dir);

my $efile = $dir."/rec.err";
open(ERR ,">$efile") || die "cannot open new error file\n";

my $gfile = $dir."/rec.gd_cll";
open(GCELL,">$gfile") || die "cannot open the Good Cell file\n";

my $dfile = $dir."/rec.dmp";
open(BCELL,">$dfile") || die "cannot open Bad Cell file\n";


###########################
# let's find the bad cells#
###########################

#------------------------------------------------------------------------
#assigning the items of interest in a hash
# hash key key
# rec -> cell -> lib

while(<L1>)
{
$show_file=$_;

if ($show_file=~/^\S+\s+\d\.\s+(\S+)\s+(\S+)/ ||
$show_file=~/^\d\.\s+(\S+)\s+(\S+)/)
{
my ( $cell, $lib)= ($2, $1);
$hierec->{$cell}->{$lib}=1;
#making the cell & lib to exist as a hash later to be used as error
finder
}
}

#-------------------------------------------------------------------------------
# place the lib keys in an array variable for easier readability,

#&error_check;

sub error_check
{
foreach my $cell (keys %$hierec)
{
my @lib = sort keys %{ $hierec->{ $cell } };
if (@lib == 1)
{
print "$cell \t(@lib)\n";
print GCELL"$cell (@lib)\n";
}
if( @lib >1 )
{
print ERR "$cell (@lib) - Error?\n";
}
}

}
#@cell= keys %$hierec;
#print @cell;
#--------------------------------------------------------------------------------
print"#######################\n";
#&comp_2_cell_list;
sub comp_2_cell_list
{
foreach(<L2>)
{
if(~/^\s?(\S+)\s+(\S+)/)
{

my ($cadlib,$cadcell)=($1,$2);
if(! exists($hierec->{$cadcell}))
{
print "list to dump: $cadcell\n";
print BCELL "$cadcell\n";
}

# if(! exist(%{$hierec->{$cell}}->{$cadlib}))
case 1) I need to know how to fix the correct syntax to return the
desire output. this is where I need to find how to reference the
$hierec->{$cell} ;
which are the $lib found in our gold stnd to compare against the
$cadlib.

# if(%{$hierec} ne $cadlib)
case 2) I need to know why the ouput shows something in the hash but
not string


{
print "mismatch libs in:%{$hierec}
($hierec->{$cell},$cadlib)\n";
}
}
}
}
#-------------------------------------------------------------------------------

close(GCELL);
close(BCELL);
close(ERR);
 
F

Fabian Pilkowski

* perl_newbie said:
if(! exists($hierec->{$cadcell}))
{
print "list to dump: $cadcell\n";
print BCELL "$cadcell\n";
}

# if(! exist(%{$hierec->{$cell}}->{$cadlib}))
case 1) I need to know how to fix the correct syntax to return the
desire output. this is where I need to find how to reference the
$hierec->{$cell} ;
which are the $lib found in our gold stnd to compare against the
$cadlib.

In your if statement above you wrote "exists" -- now you try it with
"exist". Please look at typos first if your Perl doesn't understand what
you want. But that's not all: exists() expects a hash element instead of
a whole hash. I don't really know what you want, but try:

if ( ! exists $hierec->{$cell}->{$cadlib} )

Btw, "if not" is better written as "unless", IMHO.

unless ( exists $hierec->{$cell}->{$cadlib} )
# if(%{$hierec} ne $cadlib)

Err, the operator "ne" is for comparing two strings with each other
("not equal"). Sure, you *could* compare a hash with a string, but you
*should* not unless you know what you're doing. In this case, I cannot
help you because ...
case 2) I need to know why the ouput shows something in the hash but
not string

.... that makes no sense for me. Perhaps you could describe a bit clearer
what you want.

regards,
fabian
 
P

perl_newbie

thanks, for your input and I will work on a self-contained program to
post and have you add comments on but for now I think I'll try work on
this until i get stuck again.
thank you all for your help.
 
J

Jürgen Exner

perl_newbie said:
thanks, for your input

Who's input?
Please quote some text when you are referring to an existing posting such
that people have a chance to understand what you are talkng about.
and I will work on a self-contained program to
post and have you add comments on

That's certainly a good idea.
but for now I think I'll try work on this
until i get stuck again

What is "this"? Without you quoting some context there is no way for us to
know what you re talking about.

jue
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,060
Latest member
BuyKetozenseACV

Latest Threads

Top