SaltedPork
SaltedPork

Reputation: 377

Keeping a count while reading a file line by line

I have a file that looks like:

1
3
7
8

It has numbers that increase but not in a consistent way: it is random.

I would like a file that looks like:

1   1
2   0
3   1
4   0
5   0 
6   0
7   1
8   1

It fills in the missing numbers in the left hand column and adds a \t1 to show that it was present in the original file (0 for absent). So far I have:

#! /usr/bin/perl

use warnings;
use strict;

my $infile = $ARGV[0];

open(IN, $infile) or die ("Could not open file.");

my $counter = 0;

while ( my $line  = <IN> ) {

    chomp $line;

    if ( $counter == $line ) {
        print "$line\t1\n";
        ++$counter;
    }
    else {
        print "$counter\t0\n";
        ++$counter;
    }
}

close (IN);

output

0   0
1   0
2   0
3   0

It isn't producing the desired result. Any ideas?

Upvotes: 2

Views: 1208

Answers (3)

Borodin
Borodin

Reputation: 126722

This Perl program will do as you ask. It reads each number from the input file and prints a line with a zero for every value preceding it that hasn't been output. It then prints the input value with a one and goes to read the next number from the input

This program expects the path to the input file as a parameter on the command line and prints the output to STDOUT

use strict;
use warnings 'all';

my $n = 1;

while ( <> ) {
      my ($f) = split;
      print $n++, "\t0\n" while $n < $f;
      print $n++, "\t1\n";
}

output

1   1
2   0
3   1
4   0
5   0
6   0
7   1
8   1

Upvotes: 4

Dada
Dada

Reputation: 6626

You are iterating over the lines of your input file, and each time printing one line, so your output only has as much lines as your input.

Instead, you want to keep a counter (like you did), and for each line, while that counter is less that the number on the line, print $counter 0, because that number is not present in your input:

#! /usr/bin/perl
use warnings;
use strict;

my $infile = $ARGV[0];

open (my $in, '<', $infile) or die ("Could not open file: $!.");

my $counter = 0;
while ( my $line  = <$in> ) {
    chomp $line;
    while ( ++$counter < $line ) {
        print "$counter\t0\n"
    }
    print "$line\t1\n" # or 'print "$counter\t1\n"', whichever you find clearer
}

close $in;

Also, note that I've use a 3 arguments open, and a lexical variable $in for your filehandle instead of your IN, and I've included $! in the error message so if something goes wrong, you'll know what it was.

Upvotes: 6

simbabque
simbabque

Reputation: 54323

One way to do this is to add a second loop that keeps counting up until you have a match.

use strict;
use warnings;

my $counter = 1;
LINE: while( my $line  = <DATA>) {
    chomp $line;
    while () {
        if ($counter == $line) {
            print "$counter\t1\n";
            $counter++;
            next LINE;
        }
        else {
            print "$counter\t0\n";
            $counter++;
        }
    }
}

__DATA__
1
3
7
8

This makes use of the infinite loop while () { ... } construct, as well as a label (LINE:) on the outer loop and the next LABEL keyword, which breaks out of the inner loop and skips to the next iteration of the loop with the label. Since we're counting after comparing, we need to start with 1.

Upvotes: 2

Related Questions