Question

I have these two files which I would like to compare its contents numerically.

Text1:

C_A C_A 0.0000 0.0000 0 0 50 47 100 390
C_A/I0/I0 INV 0.0200 0.2210 0 0 20 200 30 100
C_A/I0/I2 INV 1.0400 0.2210 0 0 530 200 250 261

Text2:

C_A C_A 0.0000 0 0 0 50 47 100 390
C_A/I0/I0 INV 0.0200 0.2213 0 0 20 200 30 100
C_A/I0/I2 INV 1.04 0.2210 0 0 530 200.00 250 261

Desired Output:

C_A/I0/I0 INV has mismatch property.

I have tried this so far but I got errors of use of uninitialized value. Please do advise me. Thanks for your help in advance.

Edited CODE:

use strict;
use warnings;
my %ref_data;

open my $fh, '<', 'Text1' or die $!;
while (<$fh>) {
    chomp;
    my ($occurname, $tempname, @data) = split;
    $ref_data{$occurname} = \@data;
    }

open $fh, '<', 'Text2' or die $!;
while (<$fh>) {
    chomp;
    my ($occurname, $tempname, @data1) = split;
    my $data = $ref_data{$occurname};
    print "$occurname $tempname has mismatch property\n" if 
        grep { $data1[$_] != $data->[$_] } 0 .. $#data1;
      }
    } 
Was it helpful?

Solution 2

How about the smartmatch operator?

while (<$fh>) {
    my ($occurname, $tempname, @data1) = split;
    my $data = $ref_data{$occurname};
    print "$occurname $tempname has mismatch property\n" unless @$data ~~ @data1;
}

If your Perl is not new enough (< 5.10.1), just use TLP's idea.

EDIT: Added check for matching array lengths to stifle uninitialized value warnings when arrays are not the same size.

if (@data1 != @$data || grep { $data1[$_] != $data->[$_] } 0 .. $#data1) {
    print "$occurname $tempname has mismatch property\n";
}

See grep

Also section on arrays here for $#array

OTHER TIPS

Perhaps the following will be helpful:

use strict;
use warnings;

my $file2 = pop;
my %ref_data;

while (<>) {
    my ( $occurname, $tempname, @data1 ) = split;
    $ref_data{$occurname} = \@data1;
}

push @ARGV, $file2;

while (<>) {
    my ( $occurname, $tempname, @data2 ) = split;
    my $data1 = $ref_data{$occurname};

    for ( 0 .. $#data2 ) {
        if ( $data1->[$_] != $data2[$_] ) {
            print "$occurname $tempname has mismatch property\n";
            last;
        }
    }
}

Usage: >perl script.pl Text1 Text2 [>outFile]

The last, optional parameter directs output to a file.

Output on your data sets:

C_A/I0/I0 INV has mismatch property

This lets Perl handle the file i/o. Also, a for loop is used to compare array contents--instead of grep--since it can be quickly terminated if a mismatch is found.

You could pack them, in a integer mode and then compare the packed values..

  unpack('s', $val1) != unpack('s', $val2);

Note from perldoc: But don't expect miracles: if the packed value exceeds the allotted byte capacity, high order bits are silently discarded, and unpack certainly won't be able to pull them back out of some magic hat. And, when you pack using a signed template code such as s, an excess value may result in the sign bit getting set, and unpacking this will smartly return a negative value.

Depending on how precise you need to be, I would just subtract the two and test for it being very close to zero:

if ( grep { my $delt= $data[$_] - $data1[$_] ;  return ( $delt < -1e-16 ) || ( $delt > 1e-16 ) ; } 1..$#data

Notice I changed the range from 0..$data to 1..$#data. You don't need to compare the first field since its text.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top