LoginSignup
1
0

More than 1 year has passed since last update.

【AtCoder】TypeScript で Python の `input()` ライクな入力を実現する

Last updated at Posted at 2022-08-20

Python の input() のように、入力を1行ずつ読み込むような関数を実現する TypeScript のテンプレートを作成しました。

main.ts
import { readFileSync } from "fs";
let inputLinesIndex = 0;
const inputLines = readFileSync("/dev/stdin", "utf8").split("\n");
const input = () => inputLines[inputLinesIndex++];

// おまけ
// Python の `print()` に似た関数
const print = (...messages: any) => console.log(...messages);

input() を呼び出すたびに inputLinesIndex がインクリメントし、結果的に1行ずつ読み込まれるような挙動を実現できます。

TypeScript (3.8) (AtCoder の 2022/08/21 現在のバージョン)で動作することを確認済みです。

追記:input() 以外の Python ライクな機能も TypeScript で実装した、という記事を書きました。

以下、Python での例と並べて代表的な使用例を記載します。

使用例

文字列1行

$S$

例:ABC 260 A - A Unique Letter

文字列として1行読み込むだけ。

main.py
S = input()
main.ts
import { readFileSync } from "fs";
let inputLinesIndex = 0;
const inputLines = readFileSync("/dev/stdin", "utf8").split("\n");
const input = () => inputLines[inputLinesIndex++];

const S = input();

整数1個

$N$

例:ABC 256 A - 2^N

整数を1つだけ読み込む。

main.py
N = int(input())
main.ts
import { readFileSync } from "fs";
let inputLinesIndex = 0;
const inputLines = readFileSync("/dev/stdin", "utf8").split("\n");
const input = () => inputLines[inputLinesIndex++];

const N = +input();
// 下記と同等です。
// const N = Number(input());

+をつけるだけで number 型になります。

整数2個以上

$L_1\ R_1\ L_2\ R_2$

例:ABC 261 A - Intersection

1行に2個以上の場合は 分割代入 を使うと便利です。

main.py
L1, R1, L2, R2 = map(int, input().split())
main.ts
import { readFileSync } from "fs";
let inputLinesIndex = 0;
const inputLines = readFileSync("/dev/stdin", "utf8").split("\n");
const input = () => inputLines[inputLinesIndex++];

const [L1, R1, L2, R2] = input().split(" ").map(Number);

.map(Number) をつけなければ string 型として代入されます。

配列(リスト)

$N$
$A_1\ A_2\ \dots\ A_N$

例:ABC 256 B - Batters

main.py
N = int(input())
A = list(map(int, input().split()))
# 内包表記でもOK
# A = [int(x) for x in input().split()]
main.ts
import { readFileSync } from "fs";
let inputLinesIndex = 0;
const inputLines = readFileSync("/dev/stdin", "utf8").split("\n");
const input = () => inputLines[inputLinesIndex++];

const N = +input();
const A = input().split(" ").map(Number);

縦方向の配列

$N$
$W_1$
$W_2$
$\vdots$
$W_N$

例:ABC 109 B - Shiritori

main.py
N = int(input())
W = [input() for _ in range(N)]
main.ts
import { readFileSync } from "fs";
let inputLinesIndex = 0;
const inputLines = readFileSync("/dev/stdin", "utf8").split("\n");
const input = () => inputLines[inputLinesIndex++];

const N = +input();
const W = [...Array(N)].map(() => input());

$W_i$ が数値なら input()+input() にします。

タプルの配列

$N$
$A_1\ B_1$
$\vdots$
$A_N\ B_N$

例:ABC 181 B - Trapezoid Sum

main.py
N = int(input())
AB: "list[tuple[int, int]]" = [tuple(map(int, input().split())) for _ in range(N)]
main.ts
import { readFileSync } from "fs";
let inputLinesIndex = 0;
const inputLines = readFileSync("/dev/stdin", "utf8").split("\n");
const input = () => inputLines[inputLinesIndex++];

const N = +input();
const AB: [number, number][] = [...Array(N)]
  .map(() => input().split(" "))
  .map(([a, b]) => [+a, +b]);

// 関数化したもの
const inputPairArray = (n: number): [number, number][] =>
  [...Array(n)].map(() => input().split(" ")).map(([a, b]) => [+a, +b]);
// const AB = inputPairArray(N);

型を適切につけるためにちょっと面倒なことをしています(もっとシンプルに書ける方法もあるかもしれません)。

型が number[][] で構わない場合や、そもそもタプルの配列ではなく 配列A配列B で別々に管理する場合は、異なる書き方になるでしょう。

私はなるべく for 文を使わない方法(関数型っぽい方法?)を好んでいます。

2022/09/09 追記

型アサーションを使った方法を思いつきました。型アサーションの使用を許容できれば、こちらのほうがシンプルで拡張性が高いので良いと思います。

main.ts
import { readFileSync } from "fs";
let inputLinesIndex = 0;
const inputLines = readFileSync("/dev/stdin", "utf8").split("\n");
const input = () => inputLines[inputLinesIndex++];

const N = +input();
const AB = [...Array(N)].map(
  () => input().split(" ").map(Number) as [number, number]
);

// 関数化したもの
const inputPairArray = (n: number) =>
  [...Array(n)].map(() => input().split(" ").map(Number) as [number, number]);
// const AB = inputPairArray(N);

終わりに

今まで競プロではほぼ Python しか使ってきませんでしたが、TypeScript も結構書き心地が良いです。

Python と比べて、

  • 配列のメソッドチェーン(mapfilter など)の最中に一時変数をつくることができる
    • Python で同等のことはおそらく不可能
  • きちんと型のついた小さい関数をさらっと作れる
    • Python だとトップレベルのラムダ式に型をつけるのは面倒
    • 普通に def で定義するのはおおげさな場合がある

などの点で優位性を感じます。

とはいえ、Python の内包表記や、itertoolscollections などの標準ライブラリの機能は非常に強力なので、本番ではこれからも基本的には Python(というか PyPy)を使っていくでしょう(C++ はいつまで経っても慣れないので……)。

新しい入力パターンに出くわしたら、またこの記事に追記していきます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0