Beefy Boxes and Bandwidth Generously Provided by pair Networks kudra
Perl Monk, Perl Meditation
 
PerlMonks  

Merge the difference between two files and save it on the first file. Also update the first file with info in second file.

by Shariq (Initiate)
on Oct 10, 2013 at 14:13 UTC ( #1057738=perlquestion: print w/ replies, xml ) Need Help??
Shariq has asked for the wisdom of the Perl Monks concerning the following question:

Hi! I need help in merging the difference between two files and saving in the first file. following are my example files:
File 1:
A=hello
B=world

File 2:
B=planet
C=universe

After performing the operation:

File 1:
A=hello
B=planet
C=universe

Could someone kindly guide me to the right direction.
Thanks in advance

Comment on Merge the difference between two files and save it on the first file. Also update the first file with info in second file.
Re: Merge the difference between two files and save it on the first file. Also update the first file with info in second file.
by LanX (Abbot) on Oct 10, 2013 at 14:21 UTC
    > Could someone kindly guide me to the right direction.

    Sure! :)

    Firstly start with an example that makes sense (why is "world" excluded, it's different!?!) and then show us what you tried so far!

    Cheers Rolf

    ( addicted to the Perl Programming Language)

      Hi! I cam across this example which is supposed to put the difference of the two files in b_array. Then i was thinking of merging it. But it still doesn't solve my problem of updating the file with latest values.
      use strict; use warnings; use constant { FILE_A => './kma', FILE_B => './kma2', }; my %a_hash; my @a_array; my @b_array; open my $a_fh, "<", FILE_A; while ( my $line ~= <$a_fh> ) { chomp $line; $line = /^(.+?);/; # This strips the first field from the line $a_hash{$1} = 1; # Now, I'll use the first field as my index + to my hash push @a_array, $line; # This adds the line to the end of the arra +y } close $a_fh; open my $b_fh, "<", FILE_B; while ( my $line = <$b_fh> ) { $line ~= /^(.+?);/; if ( not exists $a_hash{$1} ) { push @b_array, $line; } } close $b_fh; my @combined_array = sort (@a_array, @b_array); print "content of my combined array = @combined_array";
      "world" is excluded because it has been updated by the second file.
Re: Merge the difference between two files and save it on the first file. Also update the first file with info in second file.
by McA (Deacon) on Oct 10, 2013 at 14:24 UTC

    Hi,

    read the first file line by line. Split the line at the '='. Take the first part as key of a hash and the second as value of that key. Then do the same for the second file. When you hit in the second file a key which was already read than the value gets substituted. When you have read both files print every tuple (key, value) of your resulting hash to the first file.

    When you have problems with some of that subtasks show us your code and we'll help you.

    McA

      Thanks guys. Especially McA and Corion. I have this figured. This is what I have done so far and it seems to work. Please suggest any improvements or blunders that I am making with the code.
      use strict; use warnings; use constant { FILE_A => './kma', FILE_B => './kma2', }; my %a_hash; my @a_array; my @b_array; open my $a_fh, "<", FILE_A; while (<$a_fh>) { chomp; my ($key, $value) = split '=', $_, 2; $a_hash{$key} = $value; } open my $b_fh, "<", FILE_B; while (<$b_fh>) { chomp; my ($key, $value) = split '=', $_, 2; $a_hash{$key} = $value; } open my $c_fh, ">", FILE_A or die $!; print $c_fh "$_=$a_hash{$_}\n" for (keys %a_hash);
        Nicely done.

        Funny that it felt like a homework assignemnt, showing that homework sometimes does reflect the real world :-).

        That said, I can't see any particular issue with yoru code, other than the use of a variable for the file handle, which I'm seeing more and more of in Perl posts here. Has that become the "new normal"?

        What you just did with that code, by the way, is essentially re-invent the sort/merge using Perl hashes to take care of all the dirty work for you. :-)

        Looking forward to your next Perl issue.

        > Please suggest any improvements

        Your example suggested that you want sorted output

        print $c_fh "$_=$a_hash{$_}\n" for (sort keys %a_hash);

        Cheers Rolf

        ( addicted to the Perl Programming Language)

        Just some suggestions

        The use constant part is not needed probably, you can add the filename in the open line (saving some typing).

        You have two pairs of variables with the same name for file A and File B ($key, $key, $value, $value). This is probably a source of future troubles.

        You don't need to repeat the word array as variable name, if something begins with @ you know yet that is an array, something like "@first" is probable a better choice, (easier to write and read) than "@a_array". Don't use @a either.

        You need to add possible spaces to the split regex, and you could probably fill the %hash directly with maybe something like: (untested)

        my ($key, $a_hash{$key}) = split /\s*=\s*/, $_, 2;
Re: Merge the difference between two files and save it on the first file. Also update the first file with info in second file.
by marinersk (Chaplain) on Oct 10, 2013 at 15:42 UTC
    Nice homework exercise. Forces you to read a file, write a file, and conceptually divides the I/O from the processing by requiring information from both files before writing the output.

    There are many ways to do this, but for such a small amount of data (homework exercise unlikely to exceed your system's memory LOL), I'd agree McA on this one -- a hash is definitely the way to go. That does most of the work for you.

      Actually it is an interesting exercise. What I need this is for remotely configuring my WiFi access points that runs with hostapd. So hostapd has a configuration file called hostapd.conf.

      what I want is to send only the modifications in the conf file over a perl socket. I am able to do that already. But now I need to process the downloaded file and merge into the existing conf file and then reboot the AP.

      I am new to perl so i am stuck for the time being :)
Re: Merge the difference between two files and save it on the first file. Also update the first file with info in second file.
by Laurent_R (Priest) on Oct 10, 2013 at 17:07 UTC

    The specifications you gave don't make sense. Please explain.

      Sorry about that. What I need is that. I have one text file and then I get a second text file. Then I want the contents in the first text file to be updated by the content of the second text file.
Re: Merge the difference between two files and save it on the first file. Also update the first file with info in second file.
by Lennotoecom (Monk) on Oct 10, 2013 at 20:27 UTC
    #./script.pl file1 file2
    %hash = map {$_ => 1} <>; open OUT, '> file3' or die $!; print OUT for (sort keys %hash);
    i wouldn't change the original file1
    hence file3 as output

      This is wrong. For example for the two given input files, your code gives the following output:

      %hash = map {$_ => 1} <DATA>; print for (sort keys %hash); __DATA__ A=hello B=world B=planet C=universe
      Output:
      A=hello B=planet B=world C=universe

      ... but the expected output is

      A=hello B=planet C=universe

      The input data is basically a two-column input and the keys are in the first column. The hash approach in general is correct, but you need to use the stuff left of the equal sign as key and the rest (or the whole line) as value:

      use strict; my %hash = map {/^(.*)=/ or die "Malformed input: $_"; $1 => $_} <DATA +>; print for (sort values %hash); __DATA__ A=hello B=world B=planet C=universe
        when I wrote that, the author didnt clarify
        the tasks clearly yet
        if he needs select the name before "="
        i would go with code:
        %hash = map {/=(\w+)/; $` => $1} <DATA>; foreach (sort keys %hash){ print "$_ $hash{$_}\n"; } __DATA__ A=hello B=world B=planet C=universe
Re: Merge the difference between two files and save it on the first file. Also update the first file with info in second file.
by hdb (Parson) on Oct 14, 2013 at 07:03 UTC

    As a one-liner: (make sure you keep a copy of file1 around...)

    perl -ne "/^([^=]+)/ and $_{$1}=$_; END {print sort values %_}" file1 +file2 > file1

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (6)
As of 2014-04-18 22:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (472 votes), past polls