Skip to content

Instantly share code, notes, and snippets.

@agoalofalife
Last active April 19, 2017 09:13
Show Gist options
  • Save agoalofalife/88255db373d6d69ef3b2ac06adcaad86 to your computer and use it in GitHub Desktop.
Save agoalofalife/88255db373d6d69ef3b2ac06adcaad86 to your computer and use it in GitHub Desktop.
statistic.go
package main
import (
"fmt"
"log"
"net/http"
"sort"
"strconv"
"strings"
"math"
)
const (
pageTop = `<!DOCTYPE HTML><html><head>
<style>.error{color:#FF0000;}</style></head><title>Statistics</title>
<body><h3>Statistics</h3>
<p>Вычисляет основные статистические данные для заданного списка чисел</p>`
form = `<form action="/" method="POST">
<label for="numbers">Numbers (comma or space-separated):</label><br />
<input type="text" name="numbers" size="30"><br />
<input type="submit" value="Calculate">
</form>`
pageBottom = `</body></html>`
anError = `<p class="error">%s</p>`
)
type statistics struct {
numbers []float64
mean float64
median float64
mode []float64
dev float64
}
func main() {
http.HandleFunc("/", homePage)
if err := http.ListenAndServe(":9001", nil); err != nil {
log.Fatal("failed to start server", err)
}
}
func homePage(writer http.ResponseWriter, request *http.Request) {
err := request.ParseForm()
fmt.Fprint(writer, pageTop, form)
if err != nil {
fmt.Fprintf(writer, anError, err)
} else {
if numbers, message, ok := processRequest(request); ok {
stats := getStats(numbers)
fmt.Fprint(writer, formatStats(stats))
} else if message != "" {
fmt.Fprintf(writer, anError, message)
}
}
fmt.Fprint(writer, pageBottom)
}
func processRequest(request *http.Request) ([]float64, string, bool) {
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) {
stats.numbers = numbers
sort.Float64s(stats.numbers)
stats.mean = sum(numbers) / float64(len(numbers))
stats.median = median(numbers)
stats.mode = getMode(numbers)
stats.dev = dev(numbers)
return stats
}
func sum(numbers []float64) (total float64) {
for _, x := range numbers {
total += x
}
return total
}
func median(numbers []float64) float64 {
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>
<tr><td>Mode</td><td>%v</td></tr>
<tr><td>Std Dev.</td><td>%f</td></tr>
</table>`, stats.numbers, len(stats.numbers), stats.mean, stats.median, stats.mode, stats.dev )
}
func dev(numbers []float64) (dev float64){
var middle float64
for _,val := range numbers {
middle += val
}
middle = middle / float64(len(numbers))
for _,val := range numbers {
fmt.Println(math.Pow(val - middle, 2))
dev += math.Pow(val - middle, 2)
}
dev = dev / float64(len(numbers) - 1)
return math.Sqrt(dev)
}
func getMode( numbers []float64 ) (top []float64) {
var state bool
m := make(map[float64]float64)
numbersOne := make([]float64, len(numbers))
copy(numbersOne, numbers)
for _ , oneIterate := range numbersOne{
m[oneIterate], state = countMatches(numbersOne, oneIterate);
deleteElement(numbersOne, oneIterate)
}
var values []float64
for _, count := range m {
values = append(values, count)
}
sort.Sort(sort.Reverse(sort.Float64Slice(values)))
//fmt.Println(Ints(values))
if len(values) > 2 && state {
top = getKeyOnlyUp( values[0] , m)
}
return top
}
func countMatches( where []float64, what float64) (counter float64, err bool) {
for _, value := range where{
if what == value{
counter += 1
}
}
if counter < 1 {
return counter, false
}
return counter, true
}
func deleteElement( where []float64, what float64) (newArr []float64) {
for _, value := range where{
if what != value{
newArr = append(newArr, value)
}
}
return newArr
}
func getKeyOnlyUp(key float64, hash map[float64]float64) (top []float64){
for value, count := range hash {
if count == key {
top = append(top, value)
}
}
return top
}
func Ints(input []float64) []float64 {
u := make([]float64, 0, len(input))
m := make(map[float64]bool)
for _, val := range input {
if _, ok := m[val]; !ok {
m[val] = true
u = append(u, val)
}
}
return u
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment