Kernighans large earthquake problem
You are encouraged to solve this task according to the task description, using any language you may know.
Brian Kernighan, in a lecture at the University of Nottingham, described a problem on which this task is based.
- Problem
You are given a a data file of thousands of lines; each of three `whitespace` separated fields: a date, a one word name and the magnitude of the event.
Example lines from the file would be lines like:
8/27/1883 Krakatoa 8.8 5/18/1980 MountStHelens 7.6 3/13/2009 CostaRica 5.1
- Task
- Create a program or script invocation to find all the events with magnitude greater than 6
- Assuming an appropriate name e.g. "data.txt" for the file:
- Either: Show how your program is invoked to process a data file of that name.
- Or: Incorporate the file name into the program, (as it is assumed that the program is single use).
ALGOL 68
<lang algol68>IF FILE input file;
STRING file name = "data.txt"; open( input file, file name, stand in channel ) /= 0
THEN
# failed to open the file # print( ( "Unable to open """ + file name + """", newline ) )
ELSE
# file opened OK # BOOL at eof := FALSE; # set the EOF handler for the file # on logical file end( input file, ( REF FILE f )BOOL: BEGIN # note that we reached EOF on the latest read # at eof := TRUE; # return TRUE so processing can continue # TRUE END ); # return the real value of the specified field on the line # PROC real field = ( STRING line, INT field )REAL: BEGIN REAL result := 0; INT c pos := LWB line; INT max pos := UPB line; STRING f := ""; FOR f ield number TO field WHILE c pos <= max pos DO # skip leading spaces # WHILE IF c pos > max pos THEN FALSE ELSE line[ c pos ] = " " FI DO c pos +:= 1 OD; IF c pos <= max pos THEN # have a field # INT start pos = c pos; WHILE IF c pos > max pos THEN FALSE ELSE line[ c pos ] /= " " FI DO c pos +:= 1 OD; IF field number = field THEN # have the required field # f := line[ start pos : c pos - 1 ] FI FI OD; IF f /= "" THEN # have the field - assume it a real value and convert it # FILE real value; associate( real value, f ); on value error( real value , ( REF FILE f )BOOL: BEGIN # "handle" invalid data # result := 0; # return TRUE so processing can continue # TRUE END ); get( real value, ( result ) ) FI; result END # real field # ; # show the lines where the third field is > 6 # WHILE NOT at eof DO STRING line; get( input file, ( line, newline ) ); IF real field( line, 3 ) > 6 THEN print( ( line, newline ) ) FI OD; # close the file # close( input file )
FI</lang>
AWK
<lang awk> awk '$3 > 6' data.txt</lang>
C
<lang c>#include <stdio.h>
- include <string.h>
- include <stdlib.h>
int main() {
FILE *fp; char *line = NULL; size_t len = 0; ssize_t read; char *lw, *lt; fp = fopen("data.txt", "r"); if (fp == NULL) { printf("Unable to open file\n"); exit(1); } printf("Those earthquakes with a magnitude > 6.0 are:\n\n"); while ((read = getline(&line, &len, fp)) != EOF) { if (read < 2) continue; /* ignore blank lines */ lw = strrchr(line, ' '); /* look for last space */ lt = strrchr(line, '\t'); /* look for last tab */ if (!lw && !lt) continue; /* ignore lines with no whitespace */ if (lt > lw) lw = lt; /* lw points to last space or tab */ if (atof(lw + 1) > 6.0) printf("%s", line); } fclose(fp); if (line) free(line); return 0;
}</lang>
- Output:
Using the given file:
Those earthquakes with a magnitude > 6.0 are: 8/27/1883 Krakatoa 8.8 5/18/1980 MountStHelens 7.6
Cixl
<lang cixl> use: cx;
'data.txt' `r fopen lines {
let: (time place mag) @@s split ..; let: (m1 m2) $mag @. split &int map ..; $m1 6 >= $m2 0 > and {[$time @@s $place @@s $mag] say} if
} for </lang>
- Output:
8/27/1883 Krakatoa 8.8 5/18/1980 MountStHelens 7.6
Kotlin
<lang scala>// Version 1.2.40
import java.io.File
fun main(args: Array<String>) {
val r = Regex("""\s+""") println("Those earthquakes with a magnitude > 6.0 are:\n") File("data.txt").forEachLine { if (it.split(r)[2].toDouble() > 6.0) println(it) }
}</lang>
- Output:
Using the given file:
Those earthquakes with a magnitude > 6.0 are: 8/27/1883 Krakatoa 8.8 5/18/1980 MountStHelens 7.6
Perl
<lang perl>perl -n -e '/(\S+)\s*$/ and $1 > 6 and print' data.txt</lang>
Perl 6
Pass in a file name, or use default for demonstration purposes. <lang perl6>$_ = @*ARGS[0] ?? @*ARGS[0].IO !! q:to/END/;
8/27/1883 Krakatoa 8.8 5/18/1980 MountStHelens 7.6 3/13/2009 CostaRica 5.1 END
map { .say if .words[2] > 6 }, .lines;</lang>
Python
Typed into a bash shell or similar: <lang python>python -c ' with open("data.txt") as f:
for ln in f: if float(ln.strip().split()[2]) > 6: print(ln.strip())'</lang>
Tcl
Inspired by awk. <lang tcl>catch {console show} ;## show console when running from tclwish catch {wm withdraw .}
set filename "data.txt" set fh [open $filename] set NR 0 ;# number-of-record, means linenumber
while {[gets $fh line]>=0} { ;# gets returns length of line, -1 means eof
incr NR set line2 [regexp -all -inline {\S+} $line] ;# reduce multiple whitespace set fld [split $line2] ;# split line into fields, at whitespace set f3 [lindex $fld 2] ;# zero-based #set NF [llength $fld] ;# number-of-fields
if {$f3 > 6} { puts "$line" }
} close $fh </lang>
zkl
<lang zkl>fcn equake(data,out=Console){
data.pump(out,fcn(line){ line.split()[-1]>6 },Void.Filter)
}</lang> <lang zkl>equake(Data(Void,
- <<<
"8/27/1883 Krakatoa 8.8\n" "5/18/1980 MountStHelens 7.6\n" "3/13/2009 CostaRica 5.1\n"
- <<<
));</lang> or <lang zkl>equake(File("equake.txt"));</lang> or <lang zkl>$ zkl --eval 'File.stdin.pump(Console,fcn(line){ line.split()[-1]>6 },Void.Filter)' < equake.txt</lang>
- Output:
8/27/1883 Krakatoa 8.8 5/18/1980 MountStHelens 7.6