Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
70
Help us understand the problem. What is going on with this article?
@cohalz

競技プログラミングにおけるScalaの標準入力を楽にする

More than 5 years have passed since last update.

AtCoderなどの競技プログラミングにおいて、Scalaの入力部分を非常に簡潔に書く方法をまとめました。

Scannerを使う

空白区切りで数字の並びを一行入力させてそれぞれ変数に代入する時を考えます。

1 2 3

Scalaっぽいコードを書くとしたら以下のようになるかと思います。


object Main {
  def main(args:Array[String]) = {
    /* 文字列を読み込み、空白で分割して配列にし、Int型にする */
    val in = readLine.split(" ").map(_.toInt) 
    val a = in(0)
    val b = in(1)
    val c = in(2)
  }
}

このような時に java.util.Scanner が使えます。
Scannerを使うと必要なだけ文字列を読み込み、パースして順に数字や単語を代入することが出来ます。

object Main {
  def main(args:Array[String]) = {
    val sc = new java.util.Scanner(System.in)
    val a = sc.nextInt //最初の整数が読み込まれる
    val b = sc.nextInt //2番目に出てきた整数が読み込まれる
    val c = sc.nextInt //3番目に出てきた整数が読み込まれる
    println(a)
    println(b)
    println(c)
  }
}

出力例:

1
2
3

また、Scannerは 改行を挟んでいても有効 です。
必要なだけ文字列を読み込みます。
この場合であれば、数字を三回入力するまで読み込みます。
入力例:

4
5
6

出力例:

4
5
6

入力が空白区切りでも改行区切りでも同じコードで動くのでわざわざ考えなくて済むのも利点です。
nextIntの他にはnextDoubleやnextLine(行読み込み: String)、next(空白で区切られた単語: String)などがあります。

変数初期化はまとめられる

Javaなどでは複数の変数を一行で宣言すると、最後の変数だけに対して右辺式が評価されます。
それに対してScalaは右辺の式を 左辺の変数すべてに対して評価 していきます。
なので、上で書いたようなScannerを使って連続して変数を初期化したい時は、以下のように簡単にまとめられます。

object Main {
  def main(args:Array[String]) = {
    val sc = new java.util.Scanner(System.in)
    val a,b,c = sc.nextInt //a,b,cと順番にnextIntで代入されていく
  }
}

コレクションに対してはScannerとfillを使う

最初にnを入力させ、次にn個の整数をListやArrayに入力するにはこう書きます。

object Main {
  def main(args:Array[String]) = {
    val sc = new java.util.Scanner(System.in)
    val n = sc.nextInt // 最初の数字を読み取る
    val list = List.fill(n)(sc.nextInt) // nextIntがn回呼ばれる
    println(list)
  }
}

入力例:

3
1
2
3

出力例:

List(1,2,3)

Arrayを使いたい場合はList.fillではなくArray.fillに変えるだけです。

多次元のコレクションを扱う

ARC021 A - DEAD ENDのような多次元を扱う場合

実はfillの一つ目の括弧の引数は可変長です。  
n個実引数を書くとn次元 になります。
m行n列の二次元コレクションを作りたい場合は以下のように書きます。

object Main {
  def main(args:Array[String]) = {
    val sc = new java.util.Scanner(System.in)
    val m,n = sc.nextInt
    val list = List.fill(m,n)(sc.nextInt)  //mとnの二つ書いてあるため二次元となる
    println(list)
  }
}

入力例:

2 3
1 2 3
4 5 6

出力例:

List(List(1, 2, 3), List(4, 5, 6))

(おまけ)標準出力についてのTips

Scalaのprintやprintlnは、 Javaと少し違います。
Any型を引数に取るので見た目上複数の引数を渡すことができ、出力することが可能です。
(追記: 可変長引数ではなくAny型でした。@xuwei_k さん訂正ありがとうございます)
表示はタプルと同じになり括弧が付くので、実際の出力には使えませんが、
デバッグで変数のチェックをしたい時には調べたい変数を並べるだけで済むので非常に楽になります。

object Main {
  def main(args:Array[String]) = {
    println(1,2) // => (1,2)と表示される
  }
}

結論

ScalaのコレクションをJavaのScannerクラスと組み合わせると非常に便利です!

70
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
cohalz
hatena-corp
「知る」「つながる」「表現する」で新しい体験を提供し、人の生活を豊かにする

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
70
Help us understand the problem. What is going on with this article?