ソース or 実行ファイルダウンロード
[github]
https://github.com/kuxuxun/go_lang_calculation_sample
[実行ファイル]
https://raw.githubusercontent.com/kuxuxun/go_lang_calculation_sample/master/calc_all_win.zip
何?
なにかサービス作ろうとしたとき、ユーザ数とか課金率とかのパターンとか いくつか出して
全パターン掛け算してなんとなくそれぞれのリターンがいくらになるか見たいじゃないですか。
いかにもエクセルな感じのお仕事ですけど、 われわれはエンジニアなのでエクセルとか可能な限り開きたくないわけじゃないですか。
なのでCSVドラッグアンドドロップすると全パターンの掛け算して吐き出すだけのスクリプトをGoでちゃちゃっと作りました。
例えば
| 想定ユーザ数 | 想定課金率 | 想定ARPPU | 
|---|---|---|
| 1000 | 0.01 | 1000 | 
| 10000 | 0.3 | 2000 | 
| 50000 | 
というデータをCSVで用意してexeにドラッグアンドドロップすると
| 想定ユーザ数 | 想定課金率 | 想定ARPPU | 計算結果 | 
|---|---|---|---|
| 1000.0000 | 0.0100 | 1000.0000 | 10000.0000 | 
| 1000.0000 | 0.0100 | 2000.0000 | 20000.0000 | 
| 1000.0000 | 0.3000 | 1000.0000 | 300000.0000 | 
| 1000.0000 | 0.3000 | 2000.0000 | 600000.0000 | 
| 10000.0000 | 0.0100 | 1000.0000 | 100000.0000 | 
| 10000.0000 | 0.0100 | 2000.0000 | 200000.0000 | 
| 10000.0000 | 0.3000 | 1000.0000 | 3000000.0000 | 
| 10000.0000 | 0.3000 | 2000.0000 | 6000000.0000 | 
| 50000.0000 | 0.0100 | 1000.0000 | 500000.0000 | 
| ... | ... | ... | ... | 
といった感じのファイルを吐き出します。
コード
package main
import (
	"encoding/csv"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"
	"code.google.com/p/go.text/encoding/japanese"
	"code.google.com/p/go.text/transform"
)
func noErrorOrPanic(err error) {
	if err != nil {
		panic(err)
	}
}
func validate(records [][]string) {
	if len(records) == 0 {
		panic("ファイルが空っすね")
	}
}
func main() {
	if len(os.Args) < 2 {
		panic("ファイルを指定してください")
	}
	file, err := os.Open(os.Args[1])
	noErrorOrPanic(err)
	defer file.Close()
	reader := csv.NewReader(transform.NewReader(file, japanese.ShiftJIS.NewDecoder()))
	var records [][]string
	for {
		record, err := reader.Read()
		if err == io.EOF {
			break
		} else {
			noErrorOrPanic(err)
		}
		records = append(records, record)
	}
	validate(records)
	header, data := records[:1][0], records[1:]
	// 転置
	var vs [][]float64 = make([][]float64, len(header))
	for _, row := range data {
		for col := 0; col < len(header); col++ {
			if v, err := strconv.ParseFloat(strings.Trim(row[col], " "), 64); err == nil {
				vs[col] = append(vs[col], v)
			}
		}
	}
	output, err := os.Create(file.Name() + ".calc.csv")
	defer output.Close()
	writer := csv.NewWriter(transform.NewWriter(output, japanese.ShiftJIS.NewEncoder()))
	writer.Write(append(header, "計算結果"))
	toStrs := func(nums []float64) []string {
		ss := []string{}
		for _, n := range nums {
			ss = append(ss, fmt.Sprintf("%.4f", n))
		}
		return ss
	}
	multipleAll := func(nums []float64) {
		r := 1.0
		for _, n := range nums {
			r = r * n
		}
		writer.Write(toStrs(append(nums, r)))
	}
	var d []float64
	walk(vs, d, multipleAll)
	writer.Flush()
}
func walk(datas [][]float64, currentDatas []float64, proc func([]float64)) {
	currentLevelDatas, nextLevelDatas := datas[:1][0], datas[1:]
	if len(nextLevelDatas) == 0 {
		for _, each := range currentLevelDatas {
			ds := append(currentDatas, each)
			proc(ds)
		}
		return
	}
	for _, each := range currentLevelDatas {
		ds := append(currentDatas, each)
		walk(nextLevelDatas, ds, proc)
	}
}
感想
営業さんやマーケターの方が何かお困りで、何か作ってあげたい、となった時、
Goだとexeにコンパイルしてちゃちゃっとばら撒けるので楽ですね。