Web総合研究所

1990年生まれ文系プログラマーのまとめ

Rubyの標準入出力

Paizaのスキルチェックしていて、Rubyのファイルの入出力についてある程度の知見が溜まってきたので、まとめます。

D,Cランクの問題で迷っていたら、試してみてください。

 

入力編

ファイルからの標準入力

Paizaのページ内にエディタがあるが、大半の人は自分のPCで開発すると思います。
私は、標準入力の使用頻度は高くないので、忘れがちです。
下記のコマンドで実行すると簡単です。

p gets # 1 2 3

インプットファイル

1 2 3

ターミナルにて実行

$ ruby Main.rb < input.txt
"1 2 3"
改行マークの除去

Paizaの問題には、標準入力に改行マークがあります。
除去するにはchompメソッドを使用します。

p gets
p gets.chomp

インプットファイル

1 2 3
1 2 3
$ ruby Main.rb < input.txt
"1 2 3\n"
"1 2 3"
標準入力を整数型にして、配列に格納する。

整数型にしないと、計算処理でエラーになります。

hoge = gets.split.map(&:to_i)
p hoge
p hoge[0] + 1

fuga = gets.split
p fuga
p fuga[0] + 1

インプットファイル

1 2 3
1 2 3

ターミナルにて実行

$ ruby Main.rb < input.txt 
[1, 2, 3]
2
["1", "2", "3"]
split.rb:7:in `+': no implicit conversion of Fixnum into String (TypeError)
        fromsplit.rb:7:in `<main>'

文字列型だとエラーになります。

データ部分の読み込み

Paizaの問題で標準入力で、よくあるのは最初の1行と、2行目以降だとデータの構造が違うことがあります。
自分が2行目以降の読み込みには、よく下記のコードを書きます。

# 1行目
p gets.split.map(&:to_i)

# 2行目以降読み込み
array_of_input = []
while s = gets
  array_of_input.push(s.split.map(&:to_i))
end
p array_of_input

インプットファイル

1 2 3
2 3 4 5 6
3 4 5 6 7

ターミナルにて実行

$ ruby Main.rb < input.txt 
[1, 2, 3]
[[2, 3, 4, 5, 6], [3, 4, 5, 6, 7]]

“while s = gets”で、標準入力の最後まで読み込むまで、1行を変数”s”に代入しています。

ヘッダー部分(最初の1行目)をインスタンス変数に格納して、その後の処理で使いやすくする。

ヘッダー部分は、仕様の根幹に関わる数値で、何回も参照する必要がでてくると思います。
classを作って、インスタンス変数に格納して、インスタンスの中で呼び出せる様にしましょう。

class Hoge
    def initialize(x, y, z)
        @x = x
        @y = y
        @z = z
    end
    
    def display
        p "x: " + @x.to_s
        p "y: " + @y.to_s
        p "z: " + @z.to_s
    end
end

x, y, z = gets.split.map(&:to_i)
hoge = Hoge.new(x, y, z)
hoge.display

インプットファイル

1 2 3
2 3 4 5 6
3 4 5 6 7

ターミナルにて実行

$ ruby Main.rb < input.txt 
"x: 1"
"y: 2"
"z: 3"

出力編

レシーバのクラスを表示する

型が不一致になることが原因で、エラーになることがあります。

a = 1
b = "1"

p a + b

上記の様な単純な例だったら、すぐに解決できますが、
デバッグしてると、クラスがわからないことがあります。
そこで、classメソッドを使用します。
classメソッドは、レシーバのクラスを返します。

hoge = "ruby"
p hoge.class #=> String

p 999999999999999.class #=> Bignum
p ARGV.class #=> Array
p self.class #=> Object
p Class.class #=> Class
p Kernel.class #=> Module
2次元配列を要素ごとに連結しつつ出力

たまに2次元配列の各要素を一行づつ連結して出力しなくてはならない場面があります。
その場合は下記のように記述すれば良いでしょう。

field = [[1,2],[3,4]]
# 連結
# 12
# 34
field.each { |f| puts f.join("")}
配列のnilを削除して計算を行う

配列にnilが混ざることも多いと思います。
nilがあって一番困るのは`inject`を使う時です。
そのような場合は、`compact`を使ってnilを削除しましょう。

array = [nil, 1, 2, 3, nil]
# nilを削除して計算
p array.compact.inject(&:+) # 6