Skip to content

Instantly share code, notes, and snippets.

@gcapell
Created September 7, 2019 02:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gcapell/c70b4d74a5a2e8fcd7a207966b6d003e to your computer and use it in GitHub Desktop.
Save gcapell/c70b4d74a5a2e8fcd7a207966b6d003e to your computer and use it in GitHub Desktop.
package main
import (
"encoding/csv"
"fmt"
"log"
"os"
"regexp"
"sort"
"strconv"
"strings"
)
var (
prefixes = lines(`
Baby Sushi
Drinks/Chill j
Drinks/Flavoured Milk
Drinks/Milky Max Fresh
Drinks/Fruit Juice Pop
Hot Food/Hamburger
Hot Food/Grilled Chicken Burger
Hot Food/Pizza Slab
Hot Food/Spaghetti
NEW!!! Icy Treats
Rice Paper Rolls
Snacks/Humus
Snacks/Muffin
Sushi/Inari Sushi (3 Pieces)
Sushi/Edamame
Sushi
Birthday Box/Birthday Box
Sandwiches & Rolls
Wraps
Salad Bowls
`)
)
type money int
func (m money) String() string {
d, c := m/100, m%100
if d > 1000 {
return fmt.Sprintf("$%d,%.3d.%.2d", d/1000, d%1000, c)
}
return fmt.Sprintf("$%d.%.2d", d, c)
}
func main() {
filenames := strings.Fields("bdaybox.csv lunch.csv recess.csv sushi.csv")
revenue := make(map[string]money)
counts := make(map[string]int)
var items []string
priceRanges := make(map[string]map[money]int)
for _, filename := range filenames {
records := readCSV(filename)
for _, r := range records {
category, fullItem, quantity, price := r[0], r[1], toInt(r[2]), toMoney(r[3])
item := generic(category+"/"+fullItem, prefixes)
itemPrices, ok := priceRanges[item]
if !ok {
itemPrices = make(map[money]int)
priceRanges[item] = itemPrices
items = append(items, item)
}
itemPrices[price]++
revenue[item] += money(quantity * int(price))
counts[item] += quantity
}
}
var totalRevenue money
for _, v := range revenue {
totalRevenue += v
}
fmt.Println("total revenue", totalRevenue)
sort.Slice(items, func(i, j int) bool {
return revenue[items[i]] > revenue[items[j]]
})
for k, v := range priceRanges {
if len(v) == 1 {
continue
}
fmt.Println(k, v)
}
fmt.Println("----------------")
var revSubtotal money
found90, found50 := false, false
for _, i := range items {
fmt.Println(revenue[i], i, counts[i])
revSubtotal += revenue[i]
if !found90 && float64(revSubtotal) > (0.9*float64(totalRevenue)) {
fmt.Println("************************")
found90 = true
}
if !found50 && float64(revSubtotal) > (0.5*float64(totalRevenue)) {
fmt.Println("#########################")
found50 = true
}
}
}
func readCSV(filename string) [][]string {
f, err := os.Open(filename)
if err != nil {
log.Fatal(err)
}
defer f.Close()
r := csv.NewReader(f)
records, err := r.ReadAll()
if err != nil {
log.Fatal(err)
}
return records
}
func toInt(s string) int {
n, err := strconv.Atoi(s)
if err != nil {
log.Fatal(err)
}
return n
}
var dollarPattern = regexp.MustCompile(`\$([0-9]+)\.([0-9]+)`)
func toMoney(s string) money {
m := dollarPattern.FindStringSubmatch(s)
if m == nil {
log.Fatal("%s no match for %v", s, dollarPattern)
}
return money(100*toInt(m[1]) + toInt(m[2]))
}
func generic(s string, prefixes []string) string {
for _, p := range prefixes {
if strings.HasPrefix(s, p) {
return p
}
}
return s
}
func lines(p string) []string {
lines := strings.Split(p, "\n")
reply := make([]string, 0, len(lines))
for _, l := range lines {
if len(l) > 0 {
reply = append(reply, l)
}
}
return reply
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment