0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【初学者向け】そもそも'入力される値'の受け取り方で困っている方々へ

Last updated at Posted at 2024-07-20
記事について(これは別に確認していただかなくて大丈夫です)
  • 自分がpaizaのプログラミングスキルチェックで「標準入力の受け取り方」という初歩の初歩から躓いたため記事にまとめました
    • したがって本記事のターゲットも「いざアルゴリズムの問題を解こうとしても入力の受け取り方が良く分からなくて進められない!!」という初学者の方々になるかと思います
      • また、かなり初歩的な個所から言及しているので回りくどい内容となっております
        予めご了承ください
  • 自分が Ruby を扱っている関係で Ruby で話を進めております
  • 入力される値は今回数値だけを題材にしております
    • また検証にはpaiza.ioを使用しております

必要となる基本知識

まずアルゴリズム以前に「入力値を受け取る」ことが出来なければ論外なので、ここを抑える必要があります

以下、paizaから提示いただいているサンプルコードの引用になります
このサンプルを基にAパート、Bパートに分けて説明を進めます

paiza - 値取得・出力サンプルコード
input_line = gets.to_i #【Aパート部分】
input_line.times do
  s = gets.chomp.split(" ")  #【Bパート部分】
  print "hello = #{ s[0] } , world = #{ s[1] }\n"
end

引用 : paiza - 値取得・出力サンプルコード

【Aパート部分】getsについて

一行目のinput_line = gets.to_iについて、「getsが何かはよく分からないが、getsto_iして変数に代入しているな」というのが分かります

まずto_iとは?

文字列を 10 進数表現された整数であると解釈して、整数に変換します。
引用:https://docs.ruby-lang.org/ja/latest/method/String/i/to_i.html

  • to_iは 文字列型 → 整数 に変換する』メソッドである

じゃあ、getsとは何なのか?

一行読み込んで、読み込みに成功した時にはその文字列を返します。 EOF に到達した時には nil を返します。
引用:https://docs.ruby-lang.org/ja/latest/method/IO/i/gets.html

  • getsは入力を読み込む』メソッドである
    1. 入力値は "文字列" として取得
    2. 入力値は "1行ずつ" 取得する
    3. 1行ずつ取得していき、取得する入力値の終端に到達したら nil を返す

getsで関係してくる 改行コード について

ここで先述のgetsの特徴である『入力値は "1行ずつ" 取得する』という特徴に注意すべき点があります。

  • それは『gets複数行の入力を受け取る場合、行の区切りとして行の末尾に改行コード"\n"を追加する』という点です
    • 「複数行の入力」 = 「改行で区切って複数の値を入力」という事から、
      各行の末尾に改行を示す改行コードという文字列が付加される
  • getsは『複数行の入力を取得する場合には各行末尾に改行コードが付加される
    • 改行コードとは \n のような文字列

以下、getsメソッドのサンプルコードの引用ですが、
出力結果には "\n" が末尾に付加されており、改行されているのが分かります。
(複数行の入力であろうというのが分かる)

getsメソッドのサンプルコード
f = File.new("oneline_file")
f.gets                       # => "This is line one\n"

引用:https://docs.ruby-lang.org/ja/latest/method/IO/i/gets.html


ここまでを踏まえて

▶ 以下、『入力値が4の場合』のサンプルコードになります

サンプルコードA:入力
4
サンプルコードA:出力結果
input = gets

# 入力値をそのまま利用
p input                     # => "4"
p input.class               # => String
p input + input             # => "44"

# `to_i`を使用
p input.to_i                # => 4
p input.to_i.class          # => Integer
p input.to_i + input.to_i   # => 8
  • 「数値 4」を入力しても、出力結果は「文字列 "4"」が返されているのが分かる
  • 入力値をそのままで計算を試みても"文字列同士の連結"と認識されたりしてしまい思ったような結果が得られない
    • このため入力値から数値での計算を行うにはto_iで数値に変換する一手間が必要となる

▶ 以下、『入力値が複数行の場合』のサンプルコードになります

  • getsメソッドの「入力値は "1行ずつ" 取得する」という特徴に一癖あります
    • 次のサンプルコードから分かるように、
      getsを呼び出すたびに入力から1行ずつ呼び出して取得』します
サンプルコードA - 2:入力
1
2
3
サンプルコードA - 2:出力結果
p gets   # => "1\n"
p gets   # => "2\n"
p gets   # => "3"
p gets   # => nil
  • また、「1行ずつ取得していき、取得する入力値の終端に到達したら nil を返す」という特徴から取得する入力の末端(入力の最終行)に到達したら "nil" を返し「それ以上は入力がありません」という事を意味します
    • よって4行目の "nil" はこれ以上は入力値が無い事を意味します

【Bパート部分】chompsplit(" ")について

getsで入力値を受け取っているのは分かった。ただ、s = gets.chomp.split(" ")で入力値を操作しているが目的は何なのか?」と思います。

じゃあ、chompとは何なのか?

self の末尾から rs で指定する改行コードを取り除いた文字列を生成して返します。
引用:https://docs.ruby-lang.org/ja/latest/method/String/i/chomp.html

  • chompはメソッドを呼び出した文字列から末尾の改行コードを取り除く』メソッドである
    • デフォルトは改行コード \n を取り除く
      • この点 paiza の問題を解く分にはデフォルトのままで問題ない

じゃあ、splitとは何なのか?

第 1 引数 sep で指定されたセパレータによって文字列を limit 個まで分割し、結果を文字列の配列で返します。
引用:https://docs.ruby-lang.org/ja/latest/method/String/i/split.html

  • splitはメソッドを呼び出した文字列を "指定した文字列で区切る" & "文字列の配列で結果を返す"』メソッドである

ここまでを踏まえて

以下、『入力値が複数行の場合』のサンプルコードになります

サンプルコードB:入力
1
2 3 4
5
サンプルコードB:出力結果
input1 = gets
input2 = gets

# 【1】単体の数字から chomp メソッドで改行コードを除き整数変換
p input1              # => "1\n"
p input1.chomp        # => "1"
p input1.chomp.to_i   # => 1

# 【2】空白区切りの複数の数字から chomp メソッドで改行コードを除き整数変換
p input2              # => "2 3 4\n"
p input2.chomp        # => "2 3 4"
p input2.chomp.to_i   # => 2

# 【3】空白区切りの複数の数字から chomp メソッドで改行コードを除き、
#      空白で分割して配列を返した上で各要素を整数変換
input2_ary = input2.chomp.split(" ")
p input2_ary          # => ["2", "3", "4"]
p input2_ary[0].to_i  # => 2
p input2_ary[1].to_i  # => 3
p input2_ary[2].to_i  # => 4
  1. 【1】について
    • 入力が複数行なので入力値を確認すると末尾に改行コードが入っているため、改行コードを除く手間が必要であることが分かる
    • 「改行コードを除いた上で整数変換」はpaiza - 値取得・出力サンプルコードs = gets.chomp.split(" ") で行っていることである
  2. 【2】について
    • 【1】とは異なり空白区切りで "2␣3␣4" のように入力値が渡されている事例
      • このまま整数変換すると先頭の"2"は変換して残るが、後続は消失してしまう
        (この点については下の [折り畳み] にて後述)
  3. 【3】について
    • 【2】の対策としてsplitメソッドで1つずつ値として取得できるように配列に格納する
      • 空白区切りなので split(" ") で要素を格納
    • これによって値が消失することなく操作可能になる
[折り畳み]【2】なぜ整数変換で先頭の数値しか残らないか

【結論】to_iの仕様である「整数とみなせない文字があればそこまでを変換対象」とする処理により後続の数値は消失する

整数とみなせない文字があればそこまでを変換対象とします。変換対象が空文字列であれば 0 を返します。

p "0x11".to_i   # => 0
p "".to_i       # => 0

引用:https://docs.ruby-lang.org/ja/latest/method/String/i/to_i.html

このことから 2␣3␣42to_i の対象として整数変換可能と認識されるが、
後続の ␣3␣4 は空白(数値ではない文字)を挟む関係で「整数とは見なされない」ため消失する

(余談)
以上より、【1】に限っては明示的に chomp で改行コードを除かなくとも「"1" は整数、"/n" はでは無い」とみなされるので期待する結果が得られる

input1      # => "1\n"
input1.to_i   # => 1

ここまでの前提知識を踏まえて以下の通り実践寄りに説明を進めます

改めて「値取得・出力サンプルコード」を解いてみる

以下の問題が出題されたとする

入力される値
2
2 5
3 4

このテストケースでは、最初の値は、その後入力される行数を示す(2行の入力がある)
2行目以降は、helloとworldの値が[,]区切りで書かれています。

期待する出力
hello = 2 , world = 5
hello = 3 , world = 4

引用 : paiza - 値取得・出力サンプルコード

[コードから分かる点]

  1. 複数行の入力である
  2. 一行の数値同士の間は半角空白(" ")で区切っている
  3. '期待する出力'から "2␣5" とそのまま扱ってはいけない
    • 一つ一つ数値として見なす必要がある

[コードから注意する点]

  1. 複数行の入力だから改行コードの除去は必要 => chompが必要
  2. 一行の数値同士の間は半角空白(" ")で区切っており、'期待する出力'から "2␣5" とそのまま扱ってはいけないのであるならば、一旦配列に格納して1要素として扱えるようにした方が無難 => split(" ")が必要

ここまでで習ったことだけで問題を解いてみる

※ベストな解答は paiza - 値取得・出力サンプルコード に示されていますが、この記事で習ったことだけを利用して解いてます。

入力される値
2
2 5
3 4
解答例コード
_input1 = gets # この変数は使用しない
input2 = gets
input3 = gets

input2_ary = input2.chomp.split(" ")
input3_ary = input3.chomp.split(" ")

p "hello = #{input2_ary[0]} , world = #{input2_ary[1]}"
p "hello = #{input3_ary[0]} , world = #{input3_ary[1]}"
出力結果
"hello = 2 , world = 5"
"hello = 3 , world = 4"

paiza - 値取得・出力サンプルコード と比べて以下のような改善点がありますが、期待する出力が確認できました。

【改善点について】

  • 問題文より、一行目の入力値 input1 を使用していない点が好ましくない
    • 「このテストケースでは、最初の値は、その後入力される行数を示す(2行の入力がある)」と説明されているため、この点を踏まえれば paiza - 値取得・出力サンプルコード に近づける
  • 同じ形で出力するのであれば繰り返し処理を用いるのがスマート

最後に

自分が初学者な立場なので色々と回りくどい表現になってしまいましたが参考になれば幸いです。
改善点など本記事に関連した内容を別記事にまたまとめたいと思います。

参考サイト、関連記事など

>基本的な入出力の受け取り方について

  1. paiza - 値取得・出力サンプルコード
  2. paiza - #08:複数行データを、配列に格納しよう

>paiza.ioの基本的な使い方について

  1. 成蹊学園 - Web プログラミングサイト paiza.io の利用方法(PDF)

>Rubyのリファレンスマニュアル

  1. 組み込みライブラリ>Stringクラス>to_i
  2. 組み込みライブラリ>IOクラス>gets
  3. 組み込みライブラリ>Stringクラス>chomp
  4. 組み込みライブラリ>Stringクラス>split

>関連記事

  1. rubyで unused variable と言われないように使わない変数にはアンダースコア(_)を使う
0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?