Solution Review: Web Application for Statistics
This lesson discusses the solution to the challenge given in the previous lesson.
package main import ( "fmt" "log" "net/http" "sort" "strconv" "strings" ) type statistics struct { numbers []float64 mean float64 median float64 } const form = `<html><body><form action="/" method="POST"> <h1>Statistics</h1> <h5>Compute base statistics for a given list of numbers</h5> <label for="numbers">Numbers (comma or space-separated):</label><br> <input type="text" name="numbers" size="30"><br /> <input type="submit" value="Calculate"> </form></html></body>` const error = `<p class="error">%s</p>` var pageTop = "" var pageBottom = "" func main() { // Define a root handler for requests to function homePage, and start the webserver combined with error-handling http.HandleFunc("/", homePage) if err := http.ListenAndServe(":3000", nil); err != nil { log.Fatal("failed to start server", err) } } func homePage(writer http.ResponseWriter, request *http.Request) { // Write an HTML header, parse the form, write form to writer and make request for numbers writer.Header().Set("Content-Type", "text/html") err := request.ParseForm() // Must be called before writing response fmt.Fprint(writer, pageTop, form) if err != nil { fmt.Fprintf(writer, error, err) } else { if numbers, message, ok := processRequest(request); ok { stats := getStats(numbers) fmt.Fprint(writer, formatStats(stats)) } else if message != "" { fmt.Fprintf(writer, error, message) } } fmt.Fprint(writer, pageBottom) } func processRequest(request *http.Request) ([]float64, string, bool) { // Capture the numbers from the request, and format the data and check for error var numbers []float64 if slice, found := request.Form["numbers"]; found && len(slice) > 0 { text := strings.Replace(slice[0], ",", " ", -1) for _, field := range strings.Fields(text) { if x, err := strconv.ParseFloat(field, 64); err != nil { return numbers, "'" + field + "' is invalid", false } else { numbers = append(numbers, x) } } } if len(numbers) == 0 { return numbers, "", false // no data first time form is shown } return numbers, "", true } func getStats(numbers []float64) (stats statistics) { // sort the values to get mean and median stats.numbers = numbers sort.Float64s(stats.numbers) stats.mean = sum(numbers) / float64(len(numbers)) stats.median = median(numbers) return } func sum(numbers []float64) (total float64) { // seperate function to calculate the sum for mean for _, x := range numbers { total += x } return } func median(numbers []float64) float64 { // seperate function to calculate the median middle := len(numbers) / 2 result := numbers[middle] if len(numbers)%2 == 0 { result = (result + numbers[middle-1]) / 2 } return result } func formatStats(stats statistics) string { return fmt.Sprintf(`<table border="1"> <tr><th colspan="2">Results</th></tr> <tr><td>Numbers</td><td>%v</td></tr> <tr><td>Count</td><td>%d</td></tr> <tr><td>Mean</td><td>%f</td></tr> <tr><td>Median</td><td>%f</td></tr> </table>`, stats.numbers, len(stats.numbers), stats.mean, stats.median) }
Get hands-on with 1400+ tech skills courses.