はじめに
Go言語を知るきっかけとするために、競技プログラミングをGo言語で記載しています。
今回は、Goで書くときに使用しているコードのテンプレートをGistに置いているので紹介します。
環境
Go 1.6補足
paizaではGoのバージョンが少し高いので、sort.StableSort が使用できるのですが、
Atcoderでは1.6のためsort.StableSort は使用できなかったです。
なので、コメントアウトしています。
コード
| package main | |
| import ( | |
| "bufio" | |
| "fmt" | |
| "os" | |
| "strconv" | |
| "strings" | |
| // "regexp" | |
| ) | |
| type Pair struct { | |
| p1, p2 interface{} | |
| } | |
| const ( | |
| initialBufSize = 1e4 | |
| maxBufSize = 1e8 | |
| ) | |
| var ( | |
| scanner = bufio.NewScanner(os.Stdin) | |
| writer = bufio.NewWriter(os.Stdout) | |
| ) | |
| func main() { | |
| buf := make([]byte, initialBufSize) | |
| scanner.Buffer(buf, maxBufSize) | |
| scanner.Split(bufio.ScanWords) | |
| // TODO:処理 | |
| fmt.Println(readFloat()) | |
| } | |
| /*========================================== | |
| * Library | |
| *==========================================*/ | |
| func write(s string) { | |
| writer.WriteString(s) | |
| } | |
| func print() { | |
| writer.Flush() | |
| } | |
| // scanner.Split(bufio.ScanWords) をコメントアウトしないと使用不可 | |
| func readLine() (s string) { | |
| if scanner.Scan() { | |
| s = scanner.Text() | |
| } | |
| return s | |
| } | |
| func readInt() (read int) { | |
| scanner.Scan() | |
| read, err := strconv.Atoi(scanner.Text()) | |
| if err != nil { | |
| panic(err) | |
| } | |
| return | |
| } | |
| func readFloat() (read float64) { | |
| scanner.Scan() | |
| read, err := strconv.ParseFloat(scanner.Text(), 64) | |
| if err != nil { | |
| panic(err) | |
| } | |
| return | |
| } | |
| func readRunes() (read []rune) { | |
| scanner.Scan() | |
| for _, v := range scanner.Text() { | |
| read = append(read, v) | |
| } | |
| return | |
| } | |
| func readString() (read string) { | |
| scanner.Scan() | |
| read = scanner.Text() | |
| return | |
| } | |
| func readStrings() (read []string) { | |
| scanner.Scan() | |
| for _, v := range scanner.Text() { | |
| read = append(read, string(v)) | |
| } | |
| return | |
| } | |
| func s2i(s string) int { | |
| var intVal, e = strconv.Atoi(s) | |
| if e != nil { | |
| panic(e) | |
| } | |
| return intVal | |
| } | |
| func i2s(i int) string { | |
| var strVal = strconv.Itoa(i) | |
| return strVal | |
| } | |
| func s2f(s string) float64 { | |
| var floatVal, e = strconv.ParseFloat(s, 64) | |
| if e != nil { | |
| panic(e) | |
| } | |
| return floatVal | |
| } | |
| func sum(i []int) int { | |
| sum := 0 | |
| for _, val := range i { | |
| sum += val | |
| } | |
| return sum | |
| } | |
| func split(s string) []string { | |
| return strings.Fields(s) | |
| } | |
| func strAry2intAry(strs []string) []int { | |
| var ret = make([]int, 0, len(strs)) | |
| for _, str := range strs { | |
| var intVal, e = strconv.Atoi(string(str)) | |
| if e != nil { | |
| panic(e) | |
| } | |
| ret = append(ret, intVal) | |
| } | |
| return ret | |
| } | |
| func intAry2strAry(nums []int) []string { | |
| var ret = make([]string, 0, len(nums)) | |
| for _, num := range nums { | |
| var strVal = strconv.Itoa(num) | |
| ret = append(ret, strVal) | |
| } | |
| return ret | |
| } | |
| func ary2str(strs []string) string { | |
| return strings.Join(strs, " ") | |
| } | |
| func reverse(res []int) []int { | |
| for i, j := 0, len(res)-1; i < j; i, j = i+1, j-1 { | |
| res[i], res[j] = res[j], res[i] | |
| } | |
| return res | |
| } | |
| func initalize(res []int, init int) { | |
| if len(res) == 0 { | |
| return | |
| } | |
| res[0] = init | |
| for i := 0; i < len(res); i++ { | |
| copy(res[i:], res[:i]) | |
| } | |
| } | |
| // | |
| // func regexpExample() { | |
| // // Your code here! | |
| // var str = "13:20" | |
| // r := regexp.MustCompile(`(\d+):(\d+)`) | |
| // fmt.Println(r.FindStringSubmatch(str)) | |
| // } | |
| // type Country struct { | |
| // gold int | |
| // silver int | |
| // blonze int | |
| // } | |
| // // 複数ソートのサンプル | |
| // func stableSortExample() []Country{ | |
| // var country = []Country { | |
| // {gold:1, silver:2, blonze:3}, | |
| // {gold:1, silver:2, blonze:3}, | |
| // {gold:1, silver:3, blonze:2}, | |
| // {gold:1, silver:3, blonze:3}, | |
| // } | |
| // sort.SliceStable(country, func(i, j int) bool { return country[i].blonze > country[j].blonze }) | |
| // sort.SliceStable(country, func(i, j int) bool { return country[i].silver > country[j].silver }) | |
| // sort.SliceStable(country, func(i, j int) bool { return country[i].gold > country[j].gold }) | |
| // return country | |
| // } |
コードについての補足
readLine
標準入力から1行読み取りをする。Revisions を見るとバレてしまうのですが、初めの方は bufio.NewScanner を使用していました。bufio.NewScanner を使用していたときは、1行を読み取るサイズがデフォルトのままだったので、
下記に記載の通り、 MaxScanTokenSize までしか読み取れていませんでした。
それに気づかずに、 Atcoder Beginner Contest 148 で試行錯誤してた際にWAしてました。。
bufio.NewScanner を使用するときには、 Buffer を呼んでバッファサイズを変更すれば良さそうです。
https://golang.org/pkg/bufio/
Gistのコードでは、下記のような感じで グローバルに reader と writer に分けて宣言し、最大バッファのサイズを指定してます。
const (
initialBufSize = 10000
maxBufSize = 1000000
)
var reader = bufio.NewReaderSize(os.Stdin, maxBufSize)
var writer = bufio.NewWriter(os.Stdout)2020/01/13 追記
上記の書き方だと、1行のサイズがおもすぎて配列に展開する際にメモリ消費量がやばかったので、やめました。Atcoder Beginner Contest 151 にて TLEしたので(本当は map 使いまくったせいなのですが)、ついでに直しました。
今は、readInt, readString, readRunes みたいなヘルパー関数用意して、word ごとに読み取ってます。
メモリ効率良さげなので
s2i s2f i2s
strconv.Atoi を書くのが面倒なので短い名前の関数にラップしているだけです。
s2i: string -> int
s2f: string -> float64
i2s: int -> string
strAry2intAry intAry2strAry
こちらも同じ系統です。
よく使う用途は、
r = readLine()
is := strAry2intAry(split(r))のような感じで、1行読み込みのときに、全部 string で返ってくるのを[]stringに変換してこれを []int に変換します。
ary2str
期待の出力する際に、 []string -> string するときがあるのでそのため用
reverse sum
あまり使わないけどあったらたまに使う程度
名前の通りの動作をしてくれます。
stableSortExample
安定ソートがほしいときに参考にして使います。
構造体の配列をソートする際に、第1ソート, 第2ソートみたいな感じでソートできるので良いです。
おわりに
paiza の方は長らく放置していたので 2019年11月頃からまたはじめました。 (Bランク完答を目指している途中です)
Atcoderの方は登録したままでコンテストに一切出ていなかったので、 ABC 148から出ております。
2020年内に Atcoderの方はレート1000は行きたいです。