How to resolve the algorithm Text processing/2 step by step in the Go programming language

Published on 12 May 2024 09:40 PM
#Go

How to resolve the algorithm Text processing/2 step by step in the Go programming language

Table of Contents

Problem Statement

The following task concerns data that came from a pollution monitoring station with twenty-four instruments monitoring twenty-four aspects of pollution in the air. Periodically a record is added to the file, each record being a line of 49 fields separated by white-space, which can be one or more space or tab characters. The fields (from the left) are: i.e. a datestamp followed by twenty-four repetitions of a floating-point instrument value and that instrument's associated integer flag. Flag values are >= 1 if the instrument is working and < 1 if there is some problem with it, in which case that instrument's value should be ignored. A sample from the full data file readings.txt, which is also used in the Text processing/1 task, follows: Data is no longer available at that link. Zipped mirror available here

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Text processing/2 step by step in the Go programming language

This program reads readings.txt, containing data for multiple instruments in a specific format: one line per day, with the following fields:

  1. Date (format yyyy-mm-dd)
  2. A series of readings pairs of numbers: reading value, and associated flag (1 if the reading is good, 0 otherwise)

It aims to determine:

  1. If the format of the data is valid, i.e., each line has the expected number of fields in the correct format.
  2. The total number of records with good readings for all instruments.
  3. The number of unique dates with good readings for all instruments.

The main function:

  1. Opens the file for reading, using os.Open.
  2. Declares three variables:
    • allGood: Counts records with good readings for all instruments.
    • uniqueGood: Counts unique dates with good readings for all instruments.
    • m: A map of dates (keys) to a boolean value indicating if an "all-good" record was seen for that date.
  3. Creates a bufio.Scanner to read the file line by line.
  4. Iterates through the lines using the Scan method.
  5. For each line:
    • Splits the line into fields using strings.Fields.
    • Checks if the number of fields is as expected using the constant fields.
    • Parses the date field using time.Parse.
    • Iterates through the remaining fields in pairs.
      • Parses the flag value and checks if it's greater than 0 (indicating a good reading).
      • If the flag is good, parses the reading value.
      • If any flag is not good, sets good to false.
  6. If all readings are good:
    • Increments allGood.
  7. Checks if the date has been seen before in the m map.
  8. If the date has been seen before, prints a message indicating a duplicate date stamp.
  9. Updates the m map with the new good value for the date.
  10. If good is true and the date was not previously marked as "all-good":
    • Increments uniqueGood.
  11. If there was an error in reading the lines, prints an error message.

After processing all lines, it prints the results:

  • Confirms data format validity.
  • Displays the count of records with all good readings.
  • Displays the count of unique dates with all good readings.

Source code in the go programming language

package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"
)

const (
	filename   = "readings.txt"
	readings   = 24             // per line
	fields     = readings*2 + 1 // per line
	dateFormat = "2006-01-02"
)

func main() {
	file, err := os.Open(filename)
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()
	var allGood, uniqueGood int
	// map records not only dates seen, but also if an all-good record was
	// seen for the key date.
	m := make(map[time.Time]bool)
	s := bufio.NewScanner(file)
	for s.Scan() {
		f := strings.Fields(s.Text())
		if len(f) != fields {
			log.Fatal("unexpected format,", len(f), "fields.")
		}
		ts, err := time.Parse(dateFormat, f[0])
		if err != nil {
			log.Fatal(err)
		}
		good := true
		for i := 1; i < fields; i += 2 {
			flag, err := strconv.Atoi(f[i+1])
			if err != nil {
				log.Fatal(err)
			}
			if flag > 0 { // value is good
				_, err := strconv.ParseFloat(f[i], 64)
				if err != nil {
					log.Fatal(err)
				}
			} else { // value is bad
				good = false
			}
		}
		if good {
			allGood++
		}
		previouslyGood, seen := m[ts]
		if seen {
			fmt.Println("Duplicate datestamp:", f[0])
		}
		m[ts] = previouslyGood || good
		if !previouslyGood && good {
			uniqueGood++
		}
	}
	if err := s.Err(); err != nil {
		log.Fatal(err)
	}

	fmt.Println("\nData format valid.")
	fmt.Println(allGood, "records with good readings for all instruments.")
	fmt.Println(uniqueGood,
		"unique dates with good readings for all instruments.")
}


  

You may also check:How to resolve the algorithm State name puzzle step by step in the Python programming language
You may also check:How to resolve the algorithm Dynamic variable names step by step in the zkl programming language
You may also check:How to resolve the algorithm Sorting algorithms/Selection sort step by step in the Clojure programming language
You may also check:How to resolve the algorithm Arbitrary-precision integers (included) step by step in the Erlang programming language
You may also check:How to resolve the algorithm Constrained genericity step by step in the Swift programming language