Kernighans large earthquake problem: Difference between revisions

From Rosetta Code
Content added Content deleted
(Promote to full task status.)
No edit summary
Line 130: Line 130:
8/27/1883 Krakatoa 8.8
8/27/1883 Krakatoa 8.8
5/18/1980 MountStHelens 7.6
5/18/1980 MountStHelens 7.6
</pre>


=={{header|Cixl}}==
<lang cixl>
use: cx;

'data.txt' `r fopen lines {
let: (time place mag) @@s split splat;
$mag @. split % next int 6 >= ~ next int 0 > and {
[$time @@s $place @@s $mag] say
} if
} for
</lang>

{{output}}
<pre>
8/27/1883 Krakatoa 8.8
5/18/1980 MountStHelens 7.6
</pre>
</pre>



Revision as of 00:20, 22 April 2018

Task
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
  1. Create a program or script invocation to find all the events with magnitude greater than 6
  2. Assuming an appropriate name e.g. "data.txt" for the file:
    1. Either: Show how your program is invoked to process a data file of that name.
    2. 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>

  1. include <string.h>
  2. 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 splat;
 $mag @. split % next int 6 >= ~ next int 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

Works with: Rakudo version 2018.03

Pass in a file name, or use default for demonstration purposes. <lang perl6>$_ = @*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>

zkl

<lang zkl>fcn equake(data,out=Console){

  data.pump(out,fcn(line){ line.strip().split(" ")[-1]>6 },Void.Filter)

}</lang> <lang zkl>equake(Data(Void,

  1. <<<

"8/27/1883 Krakatoa 8.8\n" "5/18/1980 MountStHelens 7.6\n" "3/13/2009 CostaRica 5.1\n"

  1. <<<

));</lang> or <lang zkl>equake(File("equake.txt"));</lang> or <lang zkl>$ zkl --eval 'File.stdin.pump(Console,fcn(line){ line.strip().split(" ")[-1]>6 },Void.Filter)' < equake.txt</lang>

Output:
8/27/1883    Krakatoa            8.8
5/18/1980    MountStHelens       7.6