🐶

【競プロ】Goの標準入力チートシート

2023/06/16に公開

はじめに

慣れないGoを書く機会を増やそうと思い、Goで競技プログラミングをやってみました。

慣れない言語で競技プログラミングを始めるにあたり、標準入力の壁にぶつかってしまったため、
自分の覚え書きも兼ねて、標準入力についてまとめていきたいと思います。
(AtCoderでは、何らかの入力が標準入力で与えられるため、
そもそも標準入力ができなければ"Hello, World!"の問題すら解くことができないのです…。)

今回は、私がAtCoderで解くとき用に使っているテンプレをご紹介しますが、
AtCoderだけでなく、同じく標準入力を受け取るPaizaの問題を解く際にも活かせると思います。

この記事の対象者

  • Go言語での標準入力方法を知りたい方
  • Go言語で競技プログラミングをやってみようと思っている方

基本的には、こんな標準入力の形式の場合は、こんなコードで入力を受け取れますよ、といったブログの書き方になりますので、
Go言語に慣れていない方でも気軽に読めるかなと思っています。

標準入力方法の紹介

以下の4パターンを紹介してみます。

  • 入力の数が決まっており、半角スペース区切りの場合
  • 入力の数が決まっており、区切り文字が無い場合
  • 入力の数が決まっておらず、半角スペース区切りの場合
  • 入力の数が決まっておらず、複数行に分かれている場合

入力の数が決まっており、半角スペース区切りの場合

入力パターン
A B C
S
入力例
12 34 56
hello
入力例を受け取るコード
package main

import (
	"fmt"
)

func main() {
	// 1文字ずつデータ型を指定して受け取る
	var a, b, c int                   // int型の変数を宣言
	var s string                      // string型の変数を宣言
	fmt.Scanf("%d %d %d", &a, &b, &c) // %dでint型を代入
	fmt.Scanf("%s", &s)               // %sでstring型を代入
}

入力の数が決まっており、区切り文字が無い場合

入力パターン
DEF
入力例
123
入力例を受け取るコード
package main

import (
	"fmt"
)

func main() {
	// 1文字ずつデータ型を指定して受け取る
	var d, e, f int // int型の変数を宣言
	fmt.Scanf("%1d%1d%1d", &d, &e, &f) // %1dでint型を1つずつ代入
}

入力の数が決まっておらず、半角スペース区切りの場合

区切り文字で区切って配列に格納する場合、int型では受け取れないため、
一旦string型として配列に格納した後、int型に変換します。

入力パターン
P1 P2 P3 ... Pn
入力例
12 34 56 78 90
入力例を受け取るコード
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	sc := bufio.NewScanner(os.Stdin)        // 標準入力を受け付けるスキャナ
	sc.Scan()                               // 1行分の入力を取得する
	inputs := strings.Split(sc.Text(), " ") // 半角スペース区切りでstring型として配列inputsに格納

	// 配列inputsの中身をstring→intに変換してリストに格納
	var ps []int                   // Pnを格納する配列を宣言
	for _, input := range inputs { // 配列inputsの全ての要素について実行
		p, _ := strconv.Atoi(input) // string→intに型変換
		ps = append(ps, p)          // intに型変換した値を、Pnを格納する配列に追加
	}
}

入力の数が決まっておらず、複数行に分かれている場合

入力が複数行に分かれている場合は、for文で行数分入力します。
1行に複数パラメタ書かれていることも多いため、
「入力の数が決まっておらず、半角スペース区切りの場合」と同様の入力を行います。

入力パターン
N
U1 V1
U2 V1
...
UN VN
入力例
5
1 2
3 4
5 6
7 8
9 10
入力例を受け取るコード
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {

	// 1文字ずつデータ型を指定して受け取る
	var n int           // int型の変数を宣言
	fmt.Scanf("%d", &n) // %dでint型を代入

	sc := bufio.NewScanner(os.Stdin) // 標準入力を受け付けるスキャナ

	var us []int // uの値を格納する配列を宣言
	var vs []int // vの値を格納する配列を宣言

	for i := 0; i < n; i++ { // 行数分繰り返す
		sc.Scan()                               // 1行分の入力を取得する
		inputs := strings.Split(sc.Text(), " ") // 半角スペース区切りでstring型として配列inputsに格納
		u, _ := strconv.Atoi(inputs[0])         // string→intに型変換
		v, _ := strconv.Atoi(inputs[1])         // string→intに型変換
		us = append(us, u)                      // uの配列に追加
		vs = append(vs, v)                      // vの配列に追加
	}

}

標準入力方法まとめ

以上の標準入力をまとめると例えば以下のようになります。

標準入力まとめ
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {

	//入力の数が決まっており、半角スペース区切りの場合
	//// 1文字ずつデータ型を指定して受け取る
	var a, b, c int                   // int型の変数を宣言
	var s string                      // string型の変数を宣言
	fmt.Scanf("%d %d %d", &a, &b, &c) // %dでint型を代入
	fmt.Scanf("%s", &s)               // %sでstring型を代入

	// 入力の数が決まっており、区切り文字が無い場合
	//// 1文字ずつデータ型を指定して受け取る
	var d, e, f int // int型の変数を宣言
	fmt.Scanf("%1d%1d%1d", &d, &e, &f) // %1dでint型を1つずつ代入

	// 入力の数が決まっておらず、半角スペース区切りの場合
	sc := bufio.NewScanner(os.Stdin)        // 標準入力を受け付けるスキャナ
	sc.Scan()                               // 1行分の入力を取得する
	inputs := strings.Split(sc.Text(), " ") // 半角スペース区切りでstring型として配列inputsに格納

	//// 配列inputsの中身をstring→intに変換してリストに格納
	var ps []int                   // Pnを格納する配列を宣言
	for _, input := range inputs { // 配列inputsの全ての要素について実行
		p, _ := strconv.Atoi(input) // string→intに型変換
		ps = append(ps, p)          // intに型変換した値を、Pnを格納する配列に追加
	}
	
	// 入力の数が決まっておらず、複数行に分かれている場合
	//// 1文字ずつデータ型を指定して受け取る
	var n int           // int型の変数を宣言
	fmt.Scanf("%d", &n) // %dでint型を代入

	sc := bufio.NewScanner(os.Stdin) // 標準入力を受け付けるスキャナ

	var us []int // uの値を格納する配列を宣言
	var vs []int // vの値を格納する配列を宣言

	for i := 0; i < n; i++ { // 行数分繰り返す
		sc.Scan()                               // 1行分の入力を取得する
		inputs := strings.Split(sc.Text(), " ") // 半角スペース区切りでstring型として配列inputsに格納
		u, _ := strconv.Atoi(inputs[0])         // string→intに型変換
		v, _ := strconv.Atoi(inputs[1])         // string→intに型変換
		us = append(us, u)                      // uの配列に追加
		vs = append(vs, v)                      // vの配列に追加
	}
}

手元にこれらを書いたコードを用意しておけば、競技プログラミングの本番では、コピペするだけで標準入力ができるようになりますので便利です。

おわりに

標準入力ができるようになれば、ひとまず競技プログラミングの問題が解けるようになります!
ぜひ、本記事の標準入力まとめも参考にしてみてください。

本記事が、Goで競技プログラミングをやってみるきっかけになれたら嬉しいです。
お読みいただきありがとうございました!

Discussion