By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
438,834 Members | 2,265 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 438,834 IT Pros & Developers. It's quick & easy.

compare two file contents

P: 89
Hi
I have two text files and each file contains 2 tab separated strings as below:

File R.txt

class1 12345
class2 26789
class1 4567
Feb 2 '09 #1
Share this Question
Share on Google+
12 Replies


P: 89
Hi Sorry, I submitted my post before finishing the draft.


I have two text files and each file contains 2 tab separated strings as below:

File testR.txt
class1 12345
class2 26789
class1 4567
class5 567
class3 987

and another file as below:
File testP.txt
class5 525
class7 728
class1 670
class8 34
class3 567

I need to compare both the files as below. For every record in R.txt, I have to check whether the column 1 is equal in the every record in P.txt and process further. I tried as below. But some how the search is not complete. For every record in R.txt, I have to search every record in P.txt and do the comparison.

I have posted my script below. But there seems to be some flaw in the logic and also I want to know whether this kind of search is optimal or not b'cos my record size of each file is around 5000 for R.txt and 3000 for P.txt. Thanks and let me know the problem in my script.

Expand|Select|Wrap|Line Numbers
  1. #!/usr/bin/perl
  2. $file1 = 'testR.txt';
  3. $file2 = 'testP.txt';
  4. open (R, $file1) || die ("Could not open $file!");
  5. open (P, $file2) || die ("Could not open $file!");
  6. $counter = 0;
  7. while ($Rline = <R>)
  8.         chomp $_;
  9.         my @R = split(/\s+/,$Rline);
  10.  
  11.         while ($Pline = <P>)
  12.         { 
  13.                 chomp $_;
  14.                 my @P = split(/\s+/,$Pline);
  15.                         if($R[0] eq $P[0]) {
  16.                         print "$R[0]\t$R[1]\t$P[0]\t$P[1]\n";
  17.                         }
  18.         }
  19.         close (P);
  20.         print "$counter\n";
  21.         $counter++;
  22.  
  23.  
  24. }
  25. close (R);
  26.  
  27.  
  28.  
Thanks.
Feb 2 '09 #2

KevinADC
Expert 2.5K+
P: 4,059
Your code looks like it should not work since you are closing file P after only searching the first line of file R. I'm not sure what to suggest though becuase what you are trying to do is not clear to me. Most likely you want to use a hash and search the hashes instead of searching the file over and over.
Feb 3 '09 #3

P: 89
Hi Kevin,

I can not add the file contents into a hash. In the above example, I need to check the first column of file1 and first column of file2 and if they are same, I have to process further. Basically I have to check for every element in the file1 and file2.

Thanks.
Feb 3 '09 #4

KevinADC
Expert 2.5K+
P: 4,059
Why can't you add the file contents into a hash? This way is very inefifficient but see if it works:

Expand|Select|Wrap|Line Numbers
  1. #!/usr/bin/perl
  2. $file1 = 'testR.txt';
  3. $file2 = 'testP.txt';
  4. open (R, $file1) || die ("Could not open $file!");
  5. open (P, $file2) || die ("Could not open $file!");
  6. $counter = 0;
  7. while ($Rline = <R>)
  8.         chomp $_;
  9.         my @R = split(/\s+/,$Rline);
  10.         seek P,0,0; # return to beginning of the P file
  11.         while ($Pline = <P>)
  12.         { 
  13.                 chomp $_;
  14.                 my @P = split(/\s+/,$Pline);
  15.                         if($R[0] eq $P[0]) {
  16.                              print "$R[0]\t$R[1]\t$P[0]\t$P[1]\n";
  17.                         }
  18.         }
  19.         print "$counter\n";
  20.         $counter++;
  21.  
  22.  
  23. }
  24. close (P)
  25. close (R);
  26.  
Feb 3 '09 #5

P: 89
Hi Kevin,
As a beginner Hash is always confusing. My basic objective is to check whether the 1st column in R file is equal to 1st column in P file and then take a difference between their 2nd columns to check whether they are just 100 in difference. That is for example,

Expand|Select|Wrap|Line Numbers
  1. class1 12345 
from R and
Expand|Select|Wrap|Line Numbers
  1. class1 670 
of P

1st column are same and diff is mod value of (12345 -670). I have to check for all the records in R against every record in P. Since it is confusing to think using hash, I did a search in a very primitive way.

Anyway as you had suggested, I will try to put the contents of values in a hash and try to compare the array values. I can understand that my search time comes down with this, but again bit confusing to compare the values between hashes.
Thanks again.
Feb 4 '09 #6

KevinADC
Expert 2.5K+
P: 4,059
I understand. It will be even harder because you have many duplicates "keys" in the files. Hash keys are unique so you would actually have to use something like a hash of arrays. I will see what I can come up with.
Feb 4 '09 #7

KevinADC
Expert 2.5K+
P: 4,059
Heres a rather quick write up of some code. It does what you want, I think. The output is probably much more verbose than you want but that can be changed to only display results you want, like if the diff is 100. I would run this on a small set of data since it will print out a lot of results. If it appears to work correctly the output can be modified.

Expand|Select|Wrap|Line Numbers
  1. use strict;
  2. use warnings;
  3. #use Data::Dumper;
  4. my $file1 = 'c:/perl_test/testR.txt';
  5. my $file2 = 'c:/perl_test/testP.txt';
  6. my %HoA;
  7. open (R, $file1) or  die ("Could not open $file1!");
  8. while(<R>){
  9.    chomp;
  10.    my ($k, $v) = split(/\s+/);
  11.    push @{$HoA{'R'}{$k}},$v;
  12. }
  13. close(R);
  14. open (P, $file2) or die ("Could not open $file2!");
  15. while(<P>){
  16.    chomp;
  17.    my ($k, $v) = split(/\s+/);
  18.    push @{$HoA{'P'}{$k}},$v;
  19. }
  20. close(P);
  21. #print Dumper \%HoA;
  22. foreach my $R (keys %{ $HoA{'R'} }) {
  23.    if (exists $HoA{'P'}{$R}) {
  24.       print "$R\ntestR     testP     diff\n------------------------------\n";
  25.       foreach my $classR ( @{$HoA{'R'}{$R}} ) {
  26.          foreach my $classP ( @{$HoA{'P'}{$R}} ) {
  27.             printf "%-10s%-10s%s\n",$classR,$classP,$classR-$classP;
  28.          }
  29.       }
  30.       print "\n";
  31.    }
  32.    else {
  33.       print "\n$R has no match in testP\n\n";
  34.    }
  35. }
Feb 4 '09 #8

KevinADC
Expert 2.5K+
P: 4,059
Output with your small sample data is:

Expand|Select|Wrap|Line Numbers
  1. class5
  2. testR     testP     diff
  3. ------------------------------
  4. 567       525       42
  5.  
  6. class1
  7. testR     testP     diff
  8. ------------------------------
  9. 12345     670       11675
  10. 4567      670       3897
  11.  
  12.  
  13. class2 has no match in testP
  14.  
  15. class3
  16. testR     testP     diff
  17. ------------------------------
  18. 987       567       420
  19.  
Feb 4 '09 #9

P: 89
Hi Kevin,

Thank you so much. It works.
Feb 4 '09 #10

KevinADC
Expert 2.5K+
P: 4,059
You're welcome. Hopefully it helps you learn how to use hashes and more complex data for future needs.
Feb 4 '09 #11

P: 89
Hi Kevin,
It was too helpful especially with hashes and saved lots of time rather than primitive way of searching. Thanks a lot again for your time.

Expand|Select|Wrap|Line Numbers
  1.  
  2. push @{$HoA{'P'}{$k}},$v; 
  3.  
is bit tricky. Could you please explain?
Regards
Lilly
Feb 4 '09 #12

KevinADC
Expert 2.5K+
P: 4,059
You are already familiar with the push function I assume:

push @array,$var;

This is really the same thing all be it with more brackets:

push @{$HoA{'P'}{$k}},$v;


its a hash of hash of array

$HoA{'P'} <-- top level of the hash
$HoA{'P'}{$R} <-- second level of the hash
@{ $HoA{'P'}{$R} } <-- this converts the second level of the hash into an array
push @{$HoA{'P'}{$k}},$v; <-- this adds $v to the end of the array @{$HoA{'P'}{$k}}

all the bracketing makes it look more complicated than it is. But notice the type casting is the same: @ for array.
Feb 4 '09 #13

Post your reply

Sign in to post your reply or Sign up for a free account.