Help us understand the problem. What is going on with this article?

Atcoderをjavascriptでやる時、入力値をイテレータ(反復)型として操作できるテンプレを作ってみた

目的

入力値の受け取りを単一文字列 → 改行分割した配列に置き換わることによってコーディング効率を少し上げる。
次のようなメリットを利用できる。
・改行分割のコーディングがいらなくなる
・「要素数」と「要素一覧」を切り分けやすくなる

GoF提唱のデザインパターン:イテレータを適用したつもり。

テンプレート

template.js
var input = require("fs").readFileSync("/dev/stdin", "utf8").trim().split("\n");
var obj = {
  "list" : input,
  "index" : 0,
  "max" : input.length,
  "next" : function(){
    if(!this.hasNext()){return null;}
    var returnObj = this.list[this.index];
    this.index++;
    return returnObj;
  },
  "hasNext" : function(){return (this.index < this.max);}
}
function next(){return obj.next();}
function hasNext(){return obj.hasNext();}
function Main(){
  //ここに処理入れてく
}
Main();

アンチパターンとリファクタリング結果

アンチパターンの方は、最初に下記コードがあるとする。

var input = require("fs").readFileSync("/dev/stdin", "utf8").trim();

例1:1行=1数列の場合

N
A1 A2 A3 A4 ... AN
B1 B2 B3 B4 ... BN
C1 C2 C3 C4 ... CN

anti1.js
function Main(){
  input = input.split("\n");
  var N = parseInt(input[0]);
  var aList = input[1].split(" ");
  var bList = input[2].split(" ").map((a)=>Number(a));//数値型へ変換
  var cList = input[3].split(" ");
  //配列番号指定がマジックナンバー。指定ミスが起こりやすい
}
ref1.js
function Main(){
  var N = parseInt(next());
  var aList = next().split(" ");
  var bList = next().split(" ").map((a)=>Number(a));//数値型へ変換
  var cList = next().split(" ");
  //すべてnext()に置き換えられる
}
例2:N行=1数値の場合

N
A1
A2
...
AN
Q
B1
B2
...
BQ

anti2-1.js
function Main(){
  input = input.split("\n");
  var N = parseInt(input[0]);
  var aList = new Array(N);
  for(var i = 1; i <= N; i++){
    aList[i - 1] = parseInt(input[i]);
  }
  var Q = parseInt(input[N + 1]);
  var bList = new Array(Q);
  for(var i = 0; i < Q; i++){
    bList[i] = parseInt(input[N + i + 2]);
  }
  //追加先と追加元のインデックスがずれてめんどくさい( 特にbListの追加が合ってるか不安 )
}
anti2-2.js
function Main(){
  input = input.split("\n");
  var N = parseInt(input[0]);
  input.shift();
  var aList = new Array(N);
  for(var i = 0; i < N; i++){
    aList[i] = parseInt(input[0]);
    input.shift();
  }
  var Q = parseInt(input[0]);
  input.shift();
  var bList = new Array(Q);
  for(var i = 0; i < Q; i++){
    bList[i] = parseInt(input[0]);
    input.shift();
  }
  //「常に一番上をとる」ということで各所にシフトが必要。
}
ref2.js
function Main(){
  var N = parseInt(next());
  var aList = new Array(N);
  for(var i = 0; i < N; i++){
     aList[i] = parseInt(next());
  }
  var Q = parseInt(next());
  var bList = new Array(Q);
  for(var i = 0; i < Q; i++){
     bList[i] = parseInt(next());
  }
  //最初に取るのが「要素の大きさ」であることを前提とすれば
  //あとはnext()に任せて取っていける
}

終わりに

配列を使うことが前提となる問題では、配列で扱えるよう下準備をしておく必要がある。
問題に当たるたびに相応のコーディングをしなければならないが、割と時間を食っていた。
毎回やるの嫌だったので作ってみたよというだけの話。

ちなみにCodeforcesではnext()をreadline()に書き換えるだけでOK(V8が同種の処理を持ってる)

Javaにも同種のふるまいをするクラス(java.util.Iterator)があり、そこではremove()がある。これ要る?

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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした