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

I have a text file as following:

-----------------------------

China:wd:2

Japan:wd:6

China:sg:2

Japan:sg:10

China:kng:70

Thailand:kng:6

------------------------------

I want to get output as follows and need to write the output to another file:

China:2:2:70

Japan:6:10

Thailand:6

How can I get this done?

Replies are listed 'Best First'.
Re: Reading from text file
by NetWallah (Canon) on Mar 23, 2018 at 05:52 UTC
    Welcome to perlmonks!

    You can do this by parsing each line of input, collecting the required pieces into an appropriate data structure (I suggest a hash).
    After the entire file is read, print out the results.

    We do not generally answer 'homework' questions when no effort is shown, so the following code does works, but is deliberately cryptic.

    $ perl -aF: -ne 'chomp @F;push @{$h{$F[0]}},$F[2]}{print join(":",$_ +,@{$h{$_}}),"\n" for sort keys %h' Your-file.txt China:2:2:70 Japan:6:10 Thailand:6
    I'm sure this code will generate more questions. Please post those here , showing how it conflicts with your understanding.

    Alternatively, post some code you have tried, and ask questions about which parts cause you difficulty.

                    Memory fault   --   brain fried

      perl -aF: -ne 'chomp @F;push @{$h{$F[0]}},$F[2]}{print join(":",$_,@{$ +h{$_}}),"\n" for sort keys %h'

      Are we going for golf?    :-)

      echo "China:wd:2 Japan:wd:6 China:sg:2 Japan:sg:10 China:kng:70 Thailand:kng:6" | perl -F: -le'push@{$h{$F[0]}},$F[2]}{$,=":";print$_, +@{$h{$_}}for sort keys%h' China:2:2:70 Japan:6:10 Thailand:6
Re: Reading from text file -- plain english approach
by Discipulus (Canon) on Mar 23, 2018 at 08:26 UTC
    Hello sarath92 and welcome to the monastery and to the wonderful world of Perl!

    You provoked already two more effort shown, more help (possibly) get in return golden principle.. I suggest a first steps suggetion: describe your solution in english then translate it in Perl:

    I want a program that advice me if I'm doing something wrong (hint: use strict; and use warnings also use diagnostic for first program is good).

    My program must open a file in read mode. foreach line of this file (see loops at perlintro) I must remove the trailing newline aka chomp it.

    Then I want the program to split the current line at every : and I want to append ( . is used to concatenate strings) the third field (but be aware array indexes strart from 0) to the hash value hold by the first field's key of a results hash. See again perlintro for hashes.

    When the reading loop is termineted the hash is full of your wanted results.

    I want to open a file in writing mode and looping the hash I write each one of the keys and value to that file.

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Reading from text file
by thanos1983 (Parson) on Mar 23, 2018 at 10:19 UTC

    Hello sarath92,

    Welcome to the Monastery. Although fellow Monks have already answered your question, I wanted to add something minor. I believe you are a bit of a beginner so maybe a more analytical step by step script could help you understand how to do something similar in future for your self.

    Sample of code:

    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %hash; while (<>) { # read files from command line (separate by space) e.g. i +n.txt sample.txt etc... next if /^(\s*(#.*)?)?$/; # skip blank lines and comments chomp; # lines that are not skipped remove new line character '\n' my @tmp = split /:/; # split line on column ':' if (exists $hash{$tmp[0]}) { # check if key exists in hash $hash{$tmp[0]} .= ":".$tmp[2]; # if exists append } else { $hash{$tmp[0]} = $tmp[2]; # if not exists create new element with +data } } continue { close ARGV if eof; } print Dumper \%hash; open(my $fh, '>', 'out.txt') # open file to print data or die "Could not open file 'out.txt' $!"; while( my( $key, $value ) = each %hash ){ # iterate over the hash print $fh $key.':'.$value . "\n"; # write data to file } close $fh # close file after finishing or warn "Could not close file 'out.txt' $!"; __END__ $ perl test.pl in.txt $VAR1 = { 'Thailand' => '6', 'China' => '2:2:70', 'Japan' => '6:10' }; $ cat out.txt Thailand:6 China:2:2:70 Japan:6:10

    Hope this helps, BR.

    Seeking for Perl wisdom...on the process of learning...not there...yet!
      I guess we are doing the Op's work for him. But I will make a few comments to your code. See a refactored version below.

      First, I would name the hash according to what the values mean. Unfortunately the OP didn't tell that key piece of info. Then we could have wound up with something like: $meanful_name{$country}

      I think a hash of array would be better here than a string as the value. This would among other things allow easy sorting of the values. They happen to be sorted in the example data, but sorting would be possible with an array.

      With the HoA, there is not need to check if the key exists. Perl would create it automatically. In your code, you do have to be sure that the key exists or the concatenation will throw an error. I think a better way to accomplish that would be: $hash{$tmp[0]} //= ''; This is a new operator in Perl 5.10 that sets the hash value to '' if it is not already defined. That way we eliminate the "if/else" statement and the concatenate case becomes the only one.

      In Perl, often constructs like $temp[0] wind up being strangely absent. That is because we can assign meaningful names right away with a list slice. Shown below. It is also possible to use "undef" as a left hand side value, like ($country,undef,$num) That is an alternate way of "throwing something away". Hope this helps.

      #!/usr/bin/perl use strict; use warnings; my %country_hash; while (<DATA>) { next if /^(\s*(#.*)?)?$/; # skip blank lines and comments chomp; # lines that are not skipped remove new line character '\n' my($country,$number) = (split /:/)[0,-1]; # split line on column ' +:' push @{$country_hash{$country}},$number; } foreach my $country (sort keys %country_hash) { print "$country:", join (":",@{$country_hash{$country}}), "\n"; } =Prints China:2:2:70 Japan:6:10 Thailand:6 =cut __DATA__ China:wd:2 Japan:wd:6 China:sg:2 Japan:sg:10 China:kng:70 Thailand:kng:6
Re: Reading from text file
by tybalt89 (Monsignor) on Mar 23, 2018 at 17:25 UTC
    #!/usr/bin/perl # http://perlmonks.org/?node_id=1211586 use strict; use warnings; $_ = do { local $/; <DATA> }; s/:\w+:/:/g; 1 while s/^(\w+):[\d:]*\K(\n.*?)^\1(:\d+)\n/$3$2/gsm; print; __DATA__ China:wd:2 Japan:wd:6 China:sg:2 Japan:sg:10 China:kng:70 Thailand:kng:6
Re: Reading from text file
by Anonymous Monk on Mar 23, 2018 at 12:40 UTC
    Here, let me do your job for you ...