Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

how to find differences between two huge files

by sayeevamsi (Initiate)
on Jan 24, 2008 at 18:16 UTC ( [id://664109]=perlquestion: print w/replies, xml ) Need Help??

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

Hello, I need your help to resolve an issue. I'm having two files called master and current file. both the files are delimiter files using | . Master file will have data around 18 to 20 Million. Extract file file will have around 50000 records. Every had I will get one new current file. Both the files are having same structure. I'm having 150 to 160 feilds in that file. Out of 150 feilds I will use key1 , first feild of both the files to identify record is existing or not, if existing I will have 6 other keys to compare . if 6 keys are similar of both the file we need to save that master file record in file x , if any difference in keys are found move the entire record of current to file y. That means we will compare master with current file, if any change occures we need to capture current file, if no change occures means master file. Thanks in advance Sayeevamsi
  • Comment on how to find differences between two huge files

Replies are listed 'Best First'.
Re: how to find differences between two huge files
by BrowserUk (Patriarch) on Jan 24, 2008 at 19:14 UTC

    If you load the current files 50,000 records into a hash keyed by the first field, it will consume ~50MB. That is if you only extract the key and store the entire record as the value:

    my %current; open CURRENT, '<', $currentFile or die $!; m[^ ( [^|]+ ) \| ]x and $current{ $1 } = $_ while <CURRENT>; close CURRENT;

    If you pre-split the entire record and store the fields as an array, the memory consumption goes way up. So don't do that :)

    Then you can process the master file 1 line at a time, extracting the key and looking it up in the hash. When a matching key is found, you then split both records into the fields, compare the required six and take the appropriate action according to the result.

    Altogether it might look something like the following pseudo-code. Note: I didn't really understand your description of what you need to do if the records do or dont match so I took you "file X" and "file Y" literally for this example code:

    #! perl -slw use strict; my $currentFile = 'current.dat'; my $masterFile = 'master.dat'; my $matched = 'matched.dat'; my $nomatch = 'nomatch.dat'; my %current; open CURRENT, '<', $currentFile or die $!; m[^ ( [^|]+ ) \| ]x and $current{ $1 } = $_ while <CURRENT>; close CURRENT; open X, '>', $matched or die $!; open Y, '>', $nomatch or die $!; open MASTER, '<', $masterFile or die $!; while( <MASTER> ) { if( m[^ ( [^|]+ ) \| ]x and exists $current{ $1 } ) { my $key = $1; my @master = split '\|', $_; my @current = split '\|', $current{ $key }; if( 6 == grep{ $current[ $_ ] eq $master[ $_ ] } 7, 14, 21, 30 +, 50, 119 ) { print X; ## Matched records } else { print Y; ## non-matched records } } } close MASTER; close X; close Y;

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Instead of these:
      m[^ ( [^|]+ ) \| ]x and $current{ $1 } = $_ while <CURRENT>; ... if( m[^ ( [^|]+ ) \| ]x and exists $current{ $1 } ) {
      you could do:
      (my $e=index($_,"|"))>0 and $current{substr($_,0,$e)}=$_ while <CURREN +T>; ... if((my $e=index($_,"|"))>0 and exists $current{substr($_,0,$e)) {
      It's a bit more typing, but depending on the string lengths and quantities involved, it might end up running a little faster (and the extra letters spelling out the function names may help to provide a bit of explanation about what's actually going on).

      (I guess the scope of the first temporary "$e" will be wider than necessary, given the absence of curly brackets for that "while" loop, but just a little more typing would fix that as well.)

        I don't see why you want to replace the regex? It's concise, fast and does exactly what I need it to do.

        Is it the form of the regex itself? Noone would look twice if it were m[" ( [^"]+ ) "]x, and it's exactly the same operation.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
      m[^ ( [^|]+ ) \| ]x

      Can you explain this one? Thanks.

        Sure.

        m[ ^ # From the start of the record ( # capture [^|]+ # everything that is not a pipe char ) \| # upto but excluding the first pipe char ]x

        In essence, grab the first field of a pipe delimited record into $1.

        Assumes that that field doesn't contain an escaped or quoted pipe character. Which is the normal case.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: how to find differences between two huge files
by apl (Monsignor) on Jan 24, 2008 at 19:01 UTC
    Okay. Show us the code you've written, describe the problem you had implementing it, and we'll be glad to help...

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (7)
As of 2024-04-23 20:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found