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

#!/usr/bin/perl open FH,'test.tsv'; @data=<FH>; $len=scalar (@data); for($i=1;$i<=$len;$i++){ print $data[$i]; }
I have to check whether all the values from 3rd column is 0 or not. If all the values are zero, then delete the line.
id date name1 name2 namen 123 2010-02-23 0 0.00 0 1234 2010-02-24 0 3 0
i.e from name1. if in a file all the values are zero then I should delete the entire file. from the above example, the output file should have the row:
id date name1 name2 namen 1234 2010-02-24 0 3 0

Replies are listed 'Best First'.
Re: Delete the line
by Utilitarian (Vicar) on Jul 21, 2010 at 09:55 UTC
    I suspect you are new to Perl, the comments in the code below are intended to be educational. I have used a couple of things you may not have seen before, @array[2..$#array] is a slice of an array, it can be thought of as a sub array starting at index 2 and going to the last element of the array $#array is the last index of @array

    Ok, so you have the individual records in the @data array.

    You now need to split the records and check that any of the values in the resultant array with an index > 2 are not equal to zero. If there are print the line.

    something like the following is what you are looking for.

    use strict; # These two lines use warnings;# will save you grief open (my $data_file, "<", 'test.tsv'); # better to use 3 argument ver +sion of open and to have a lexical filehandle my @data = <$data_file>; # scope your variables close( $data_file); # It's only polite to close up after yourself print $data[0]; # headers for my $line (@data[1..$#data]){ # More perlish not to use indices dir +ectly my @line = split(/\t/, $line); # split the values into an array print $line if (check_for_zero(@line)); # Use a routine to evaluate + the elements } sub check_for_zero{ # declare routine my @line = @_; # get the array we're called with for my $field (@line[2..$#line]){ # again more perlish return 1 if $field != 0; # We have a non-zero value } return 0; #if we got here we never met a non-zero value }
    print "Good ",qw(night morning afternoon evening)[(localtime)[2]/6]," fellow monks."
Re: Delete the line
by Anonymous Monk on Jul 21, 2010 at 09:30 UTC
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Delete the line
by Ratazong (Monsignor) on Jul 21, 2010 at 09:41 UTC

    Sounds you have to enhance your code by the following logic

    • in your loop, split your $data[$i] into an array containing words
    • write the line to a new array if not all of the columns 2, 3 and 4 are zero
    • after your for-loop, delete the file
    • if the new array contains entries, write them to the file (you actually recreate the file that way)
    HTH, Rata
Re: Delete the line
by moritz (Cardinal) on Jul 21, 2010 at 09:40 UTC
    Obviously you'll need to split the line to get to its fields, and then do a comparison, and only print if the comparison is successful. See perlintro.
Re: Delete the line
by jethro (Monsignor) on Jul 21, 2010 at 09:41 UTC

    Your example is wrong, you seem to have looked at name2 for the elimination decision.

    For the printing you might take a look at Text::Table which will output your table nicely formatted

Re: Delete the line
by matrixmadhan (Beadle) on Jul 22, 2010 at 03:12 UTC
    I know it's not in perl, trying out an awk variant here
    awk '{ yes=0; for ( i=3; i<=NF; i++) { if ( $i == 0 ) { yes=1; break} +} if ( yes != 1 ) { print } }' filename
Re: Delete the line
by JavaFan (Canon) on Jul 23, 2010 at 16:01 UTC
    Don't use Perl. use grep:
    grep -v '^[^ ][^ ]* *[^ ]* [.0 ]*$' input > output
    This assumes columns are separated by one or more spaces. And that the columns don't contain values like .0. or 0...0 (and that you want to keep such lines).