Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Comparing 2 arrays of hashes

by raghuprasad241 (Beadle)
on Mar 08, 2016 at 21:37 UTC ( #1157115=perlquestion: print w/replies, xml ) Need Help??

raghuprasad241 has asked for the wisdom of the Perl Monks concerning the following question:

Hello monks,

I am trying to compare two data structures for differences. My brain is on fire right now trying to figure out a way to accomplish this. Please see below code and I am sure I am doing the looping wrong on the anonymous array references to hashes. I am new to programming and I am from administration background. This is what I tried so far. Any help or inputs is greatly appreciated.

Currently I am at a point where I am trying to compare and make sure all the anonymous hash keys that anonymous array in DS1 exist in DS2 as well. Once this is done I will be going one more level deeper. Please let me know if anything is unclear.

#!/usr/bin/perl # Compare two schemas or tables for names, types and length. use v5.10; no strict; my %DS1=( PERL => [ {TABLES=>{ TABSCHEMA=>"VARCHAR(128)", TABNAME=>"VARCHAR(12 +8)", }}, # Tables and Columns are names of the tables. {COLUMNS=>{ TABSCHEMA=>"VARCHAR(128)", TABNAME=>"VARCHAR(1 +28)", COLNAME=>"VARCHAR(128)", PARTKEYSEQ=>"SMALLINT", }} ] ); my %DS2=( PERL => [ {TABLES=>{ TABSCHEMA=>"VARCHAR(256)", TABNAME=>"VARCHAR(12 +8)", }}, # Tables and Columns are names of the tables. {COLUMNS=>{ TABSCHEMA=>"VARCHAR(256)", TABNAME=>"VARCHAR(1 +28)", COLNAME=>"VARCHAR(128)", PARTKEYSEQ=>"SMALLINT", }} ] ); foreach my $schema1 (keys %DS1) { if (exists $DS2{$schema1}) { say "Schema $schema1 exist in target."; foreach my $tables1_ref (@{$DS1{$schema1}}) { foreach my $tables2_ref (@{$DS2{$schema1}}) { foreach my $tabnames1 (keys %{$tables1_ref}) { if (exists $tables2_ref->{$tabnames1}) { say "$tabnames1 exists in target schema DS2 +"; } else { say "$tabnames1 does not exist in target sc +hema DS2"; } say "\n" } } } } else { say "Schema $schema1 does not exist in target."; } }
Output for the above code is as follows:
Schema PERL exist in target. TABLES exists in target schema DS2 TABLES does not exist in target schema DS2 COLUMNS does not exist in target schema DS2 COLUMNS exists in target schema DS2

I am trying to compare the 2nd level of the data structure now. Once I got this working I will be going to the next level.

PS: please don't harass me for not using strict. I promise I am going to use strict once I figure this out.

Jr. Monk

Replies are listed 'Best First'.
Re: Comparing 2 arrays of hashes
by neilwatson (Priest) on Mar 08, 2016 at 21:40 UTC
Re: Comparing 2 arrays of hashes
by 1nickt (Abbot) on Mar 08, 2016 at 22:28 UTC

    PS: please don't harass me for not using strict. I promise I am going to use strict once I figure this out.

    You have something very important fundamentally backwards.

    strict does not exist to harass you but to help you figure it out!

    Update: I second the recommendation from neilwatson. One of the many advantages of using Test::More is how simple your syntax can be:

    #!/usr/bin/perl use strict; use warnings; use Test::More tests => 1; my ( $DS1, $DS2 ) = get_hashes(); is_deeply( $DS1, $DS2 ); sub get_hashes { my %DS1 = ( PERL => [ { TABLES => { TABSCHEMA => "VARCHAR(128)", TABNAME => "VARCHAR(128)", } }, { COLUMNS => { TABSCHEMA => "VARCHAR(128)", TABNAME => "VARCHAR(128)", COLNAME => "VARCHAR(128)", PARTKEYSEQ => "SMALLINT", } } ] ); my %DS2 = ( PERL => [ { TABLES => { TABSCHEMA => "VARCHAR(256)", TABNAME => "VARCHAR(128)", } }, { COLUMNS => { TABSCHEMA => "VARCHAR(256)", TABNAME => "VARCHAR(128)", COLNAME => "VARCHAR(128)", PARTKEYSEQ => "SMALLINT", } } ] ); return ( \%DS1, \%DS2 ); } __END__
    Output:
    1..1 not ok 1 # Failed test at 1157115.pl line 7. # Structures begin differing at: # $got->{PERL}[0]{TABLES}{TABSCHEMA} = 'VARCHAR(128)' # $expected->{PERL}[0]{TABLES}{TABSCHEMA} = 'VARCHAR(256)' # Looks like you failed 1 test of 1.
    Note, though, that this will only show the differences one at a time, so if you are looking for a comprehensive diff, this is not the way.

    Hope this helps!


    The way forward always starts with a minimal test.
Re: Comparing 2 arrays of hashes
by nysus (Vicar) on Mar 08, 2016 at 22:02 UTC
    my %ds1_tables = (); my %ds2_tables = (); foreach my $key (keys %{$DS1{PERL}[0]{TABLES}}) { $ds1_tables{$key} = 1; } foreach my $key (keys %{$DS2{PERL}[0]{TABLES}}) { $ds2_tables{$key} = 1; } foreach my $key (keys %ds1_tables) { if (!exists $ds2_tables{$key}) { print "$key does not exist in table 2.\n"; } else { print "$key exists in table 2.\n"; } }

    $PM = "Perl Monk's";
    $MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon";
    $nysus = $PM . $MCF;
    Click here if you love Perl Monks

      Hi nysus, thank you very much for the response. Exactly what I was looking for!

      New code is here.

      #!/usr/bin/perl # Compare two schemas or tables for names, types and length. use v5.10; no strict; my %tables1_lookup=(); my %tables2_lookup=(); my %DS1=( PERL => [ {TABLES=>{ TABSCHEMA=>"VARCHAR(128)", TABNAME=>"VARCHAR(12 +8)", }}, # Tables and Columns are names of the tables. {COLUMNS=>{ TABSCHEMA=>"VARCHAR(128)", TABNAME=>"VARCHAR(1 +28)", COLNAME=>"VARCHAR(128)", PARTKEYSEQ=>"SMALLINT", }} ] ); my %DS2=( PERL => [ {TABLES=>{ TABSCHEMA=>"VARCHAR(256)", TABNAME=>"VARCHAR(12 +8)", }}, # Tables and Columns are names of the tables. {COLUMNS=>{ TABSCHEMA=>"VARCHAR(256)", TABNAME=>"VARCHAR(1 +28)", COLNAME=>"VARCHAR(128)", PARTKEYSEQ=>"SMALLINT", }} ] ); foreach my $schema1 (keys %DS1) { if (exists $DS2{$schema1}) { say "Schema $schema1 exist in target."; } else { die "Schema $schema1 does not exist in target."; } # Build look up hashes with tables list for schema one from DS1. foreach my $tabhash1_ref (@{$DS1{$schema1}}) { foreach my $tables1_name (keys %{$tabhash1_ref}) { $tables1_lookup{$tables1_name}=1; } } # Build look up hashes with tables list for schema two from DS2. foreach my $tabhash2_ref (@{$DS2{$schema1}}) { foreach my $tables2_name (keys %{$tabhash2_ref}) { $tables2_lookup{$tables2_name}=1; } } foreach my $tables1_name(keys %tables1_lookup) { if (! exists $tables2_lookup{$tables1_name}) { say "$tables1_name table does not exists in target schema 2. +" } else { say "$tables1_name table exists in target schema 2" } } }
      Output is here:

      Schema PERL exist in target. COLUMNS table exists in target schema 2 TABLES table exists in target schema 2
      Looks like I need to learn how to use hashes as lookup tables :-)
Re: Comparing 2 arrays of hashes
by stevieb (Abbot) on Mar 08, 2016 at 22:12 UTC

    If all you're looking for is to ensure both hashes are the same, then I'd highly recommend Data::Compare:

    use strict; use warnings; use Data::Compare; my %DS1=( PERL => [ {TABLES=>{ TABSCHEMA=>"VARCHAR(128)", TABNAME=>"VARCHAR(128)", + }}, # Tables and Columns are names of the tables. {COLUMNS=>{ TABSCHEMA=>"VARCHAR(128)", TABNAME=>"VARCHAR(128)" +, COLNAME=>"VARCHAR(128)", PARTKEYSEQ=>"SMALLINT", }} ] ); my %DS2=( PERL => [ {TABLES=>{ TABSCHEMA=>"VARCHAR(256)", TABNAME=>"VARCHAR(128)", + }}, # Tables and Columns are names of the tables. {COLUMNS=>{ TABSCHEMA=>"VARCHAR(256)", TABNAME=>"VARCHAR(128)" +, COLNAME=>"VARCHAR(128)", PARTKEYSEQ=>"SMALLINT", }} ] ); my $same = Compare(\%DS1, \%DS2); print "$same\n"; # 0 (ie. false)

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1157115]
Approved by kevbot
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (3)
As of 2019-06-19 05:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Is there a future for codeless software?



    Results (84 votes). Check out past polls.

    Notices?
    • (Sep 10, 2018 at 22:53 UTC) Welcome new users!