Perl Weekly Challenge 117: Missing Row

by Abigail

Challenge

You are given text file with rows numbered 1-15 in random order but there is a catch one row in missing in the file.

11, Line Eleven
1, Line one
9, Line Nine
13, Line Thirteen
2, Line two
6, Line Six
8, Line Eight
10, Line Ten
7, Line Seven
4, Line Four
14, Line Fourteen
3, Line three
15, Line Fifteen
5, Line Five

Write a script to find the missing row number.

Solution

This is fairly trivial. The sum of the number \(1\) to \(15\) equals \(\sum_{i=1}^{15} i = 120\). So, if we add the sum of the line numbers in the file, and subtract this from \(120\) we get the missing row number.

Perl

First we import the sum method from List::Util:

use List::Util qw [sum];

Then we can get the answer in a one liner:

say 120 - sum <>;

We take advantage of the fact that if we use a string as a number, Perl will look at the beginning of the string, and tries to interpret that a number. It does issue a warning if there is some trailing stuff, but hey, if you don't turn on warnings, you won't see them.

Find the full program on GitHub.

We could also have used a one-liner, not requiring another module, nor having the number of lines hard coded:

perl -nE '$;+=$.-$_;END{say$.+1+$;}'

AWK

Just like in Perl, AWK looks at the beginning of a string if it's treated as a number. It won't issue a warning. So we get:

BEGIN {SUM_15 = 120}
      {sum += $1}
END   {print SUM_15 - sum}

Find the full program on GitHub.

Bash

For the Bash solution, we split the input. Bash does this already be default, splitting on white space. But we want to split on commas:

IFS=","

Now it's a matter of summing the first column, and subtracting the result from 120:

SUM_15=120
while read number tail; do ((sum += number)); done
echo $((SUM_15 - sum))

Find the full program on GitHub.

C

In C, we use the atol function to get the number at the beginning of a string.

# define SUM_15 120

int main (void) {
    char *  line    = NULL;
    size_t  len     = 0;
    size_t  str_len;
    int     sum     = 0;

    while ((str_len = getline (&line, &len, stdin)) != -1) {
        sum += atol (line);
    }
    printf ("%d\n", SUM_15 - sum);
    free (line);

    return (0);
}

Find the full program on GitHub.

Go

In Go, we use the method ReadString in an bufio object to read lines of input. On EOF, this method returns an error, which we use to break the loop. Go does have an Atoi method, but that doesn't work like atoi in C: it balks if there are non-numbers following the number at the beginning of the string. So, we're going to use Sscanf to parse the number.

func main () {
    var i      int
    var sum    int = 0
    var SUM_15 int = 120

    var reader = bufio . NewReader (os. Stdin)
    for {
        var text, err1 = reader . ReadString ('\n')
        if (err1 != nil) {
            break
        }
        var n, err2 = fmt . Sscanf (text, "%d", &i)
        if (n < 1 || err2 != nil) {
            continue
        }
        sum += i
    }
    fmt . Printf ("%d\n", SUM_15 - sum)
}

Find the full program on GitHub.

Java

In Java, we use a scanner object to read lines of input. Using Google, I found a couple of methods to convert string to integers, but all of them require the string to contain exactly an integer. No atoi equivalent.

So, we're just parsing the beginning of the string manually. We're making use of the charAt method on string objects: given an argument n, it returns the ASCII value of the nth character in the string.

import java.util.*;

public class ch1 {
    public static void main (String [] args) {
        Scanner scanner = new Scanner (System . in);
        int sum    = 0;
        int SUM_15 = 120;
        try {
            while (true) {
                String line = scanner . nextLine ();
                int i, n = 0;
                for (i = 0; i < line . length (); i ++) {
                    if (line . charAt (i) < "0" . charAt (0) ||
                        line . charAt (i) > "9" . charAt (0)) {
                        break;
                    }
                    n *= 10;
                    n += line . charAt (i) - "0" . charAt (0);
                }   
                sum += n;
            }
        }
        catch (Exception e) {
            System . out . println (SUM_15 - sum);
        }
    } 
}

Find the full program on GitHub.

Lua

To turn the beginning of a string into a number, we capture the leading digits, and use the function tonumber to make it a number:

local SUM_15 = 120
local sum = 0
for line in io . lines () do
    sum = sum + tonumber (line : match ("%d+"))
end
print (SUM_15 - sum)

Find the full program on GitHub.

Node.js

Here, we split the lines of input on a comma, and use the unary + to change a string into a number:

let SUM_15 = 120
let sum = 0

  require ('readline')
. createInterface ({input: process . stdin})   
. on              ('line', line => {
    let [num] = line . split (/,/)
    sum +=+ num
})
. on              ('close', () => console . log (SUM_15 - sum))

Find the full program on GitHub.

Python

Splitting on commas is the way to go in Python as well, and we use int to turn the string into an integer:

import fileinput

sum = 0
SUM_15 = 120

for line in fileinput . input ():
    sum = sum + int ((line . split (",")) [0])

print (SUM_15 - sum)

Find the full program on GitHub.

Ruby

Another split in Ruby, using the to_i method to turn the result into an integer:

sum = 0
SUM_15 = 120
ARGF . each_line do
    |line|
    sum += ((line . split (/,/)) [0]) . to_i
end

puts (SUM_15 - sum)

Find the full program on GitHub.


Please leave any comments as a GitHub issue.