1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

競技プログラミングでよくある入力パターンをHaskellで処理する(初級編)

Posted at

これは何?

HaskellでAtCoderに参加してみた 4日目の記事です。

本記事では初心者向けにとりあえず、問題で与えられる入力を処理するための方法を紹介します。

注意

getLineを使う方法は遅いので慣れてきたら使わないほうがいいかもしれません。
2025年11月11日現在、自分は別記事で記載予定のinteractを使う方法を採用しています。

初心者向けに(自分も初心者ですが)この方法を紹介する理由としては、ABCコンテストのA、B問題程度であれば入力サイズが小さいことが多いため、速度影への響が軽微なためです。


文字列

1行

  • 1行に1つの文字列: getLineは標準入力から1行を読み込み、Stringとして返す。
one_line_one_string.hs
main :: IO ()
main = do
  x <- getLine
  putStrLn x
cat <<'EOF' > input.txt
Hello
EOF
runghc one_line_one_string.hs < input.txt && /usr/bin/rm input.txt
Hello
  • 1行に複数の文字列を配列で受け取る]getLineで1行を読み込み、wordsStringを分割して[String]を返す。
one_line_multiple_strings.hs
main :: IO ()
main = do
  nameList <- words <$> getLine
  print nameList
cat <<'EOF' > input.txt
Taro Alice
EOF
runghc one_line_multiple_strings.hs < input.txt && /usr/bin/rm input.txt
["Taro","Alice"]
  • 1行に複数の文字列を分割して受け取る
one_line_multiple_strings2.hs
main :: IO ()
main = do
  [greeting, name] <- words <$> getLine
  print greeting
  print name
cat <<'EOF' > input.txt
Hello Alice
EOF
runghc one_line_multiple_strings2.hs < input.txt && /usr/bin/rm input.txt
"Hello"
"Alice"

複数行

  • 複数行に1つの文字列をまとめて配列で受け取る: getContentsは標準入力からすべての行を読み込み、Stringとして返す。linesで改行コードで分割して[String]を取得する。
multiple_lines_one_string.hs
main :: IO ()
main = do
  xs <- lines <$> getContents
  print xs

分割して受け取りたいかつ、行数が固定の場合には複数回getLineを呼び出して対応することも可能。

main :: IO ()
main = do
  let a = getLine
  let b = getLine
  let c = getLine
  print a
  print b
  print c
cat <<'EOF' > input.txt
A
B
C
EOF
runghc multiple_lines_one_string.hs < input.txt && /usr/bin/rm input.txt
["A","B","C"]
  • 複数行に1つの文字列を取得する(冒頭に個数が記載されている)の場合はreplicateMを使ってgetLineを複数回呼び出すほうがlinesを使う方法よりも自然かも。
multiple_lines_one_string2.hs
import Control.Monad

main :: IO ()
main = do
  n <- readLn
  wordList <- replicateM n getLine
  print wordList
cat <<'EOF' > input.txt
3
HOGE
FUGA
PIYO
EOF
runghc multiple_lines_one_string2.hs < input.txt && /usr/bin/rm input.txt
["HOGE","FUGA","PIYO"]

# #と.で構成されるグリッドの問題の場合もこれでいける
cat <<'EOF' > input.txt
3
#.#.
####
....
EOF
runghc multiple_lines_one_string2.hs < input.txt && /usr/bin/rm input.txt
["#.#","####","...."]
  • 複数行に1つの文字列を取得する(末尾に終了文字がある)の場合は全体を読み込んだ後、終了文字列の手前までをtakeWhileを使って取得する。
multiple_line_one_string3.hs
main :: IO ()
main = do
  input <- lines <$> getContents
  let sList = takeWhile (/= "END") input
  print sList
# ENDを終了文字として扱う
cat <<'EOF' > input.txt
HOGE
FUGA
PIYO
END
EOF
runghc multiple_line_one_string3.hs < input.txt && /usr/bin/rm input.txt

数値

1行

  • 1行に1つの数値を受け取る]: readLngetLineで1行を読み込み、readIOで数値に変換して返すという処理をまとめたものである。
one_line_one_int.hs
main :: IO ()
main = do
  -- n <- getLine >>= readIO :: IO Int -- readLnはgetLineとreadIOを組み合わせたもの
  n <- readLn :: IO Int
  print n
cat <<'EOF' > input.txt
3
EOF
runghc one_line_one_int.hs < input.txt && /usr/bin/rm input.txt
3
  • 1行に複数の数値を受け取る: getLineで1行を読み込み、wordsで分割し、readで数値に変換する。
one_line_multiple_int.hs
main :: IO ()
main = do
  intList <- map read . words <$> getLine :: IO [Int]
  print intList
cat <<'EOF' > input.txt
1 2 3
EOF
runghc one_line_multiple_int.hs < input.txt && /usr/bin/rm input.txt
[1,2,3]

複数行

  • 複数行に1つの数値を配列で取得する(文字列型でやっていたことにreadがついただけ)。
multiple_line_one_int.hs
main :: IO ()
main = do
  intList <- map read . lines <$> getContents :: IO [Int]
  print intList
cat <<'EOF' > input.txt
1
2
3
EOF
runghc multiple_line_one_int.hs < input.txt && /usr/bin/rm input.txt
[1,2,3]
  • 複数行に1つの数値を取得する(行数が冒頭で指定されている))
multiple_line_one_int2.hs
import Control.Monad (replicateM)

main :: IO ()
main = do
  n <- readLn :: IO Int
  intList <- replicateM n readLn :: IO [Int]
  print intList
cat <<'EOF' > input.txt
3
1
2
3
EOF
runghc multiple_line_one_int2.hs < input.txt && /usr/bin/rm input.txt
[1,2,3]
  • 複数行に1つの数値を取得する(末尾に終了文字がある)
multiple_line_one_int3.hs
main :: IO ()
main = do
  numbers <- map read . lines <$> getContents :: IO [Int]
  let intList = takeWhile (/= 0) numbers -- 終了文字列0までnumbersから値を取得する
  print intList
# 0を終了文字として扱う
cat <<'EOF' > input.txt
1
2
3
0
EOF
runghc multiple_line_one_int3.hs < input.txt && /usr/bin/rm input.txt
[1,2,3]

複数行かつ複数列

  • 複数行に複数の数値を取得して2次元配列に格納する
multiple_line_multiple_int.hs
main :: IO ()
main = do
  -- 2次元配列 [[Int]]
  intList2D <- map (map read . words) . lines <$> getContents :: IO [[Int]]
  print intList2D
cat <<'EOF' > input.txt
1 2 3
4 5 6
7 8 9
EOF
runghc multiple_line_multiple_int.hs < input.txt && /usr/bin/rm input.txt
[[1,2,3],[4,5,6],[7,8,9]]
  • 複数行に複数の数値を取得して2次元配列に格納する(行数が冒頭に提示)
multiple_line_multiple_int2.hs
import Control.Monad (replicateM)

-- 冒頭で行の数が示されている場合の二次元のinput
main :: IO ()
main = do
  [h, _] <- map read . words <$> getLine
  intList <- replicateM h $ map read . words <$> getLine :: IO [[Int]]
  print intList
cat <<'EOF' > input.txt
3 3
1 2 3
4 5 6
7 8 9
EOF
runghc multiple_line_multiple_int2.hs < input.txt && /usr/bin/rm input.txt
[[1,2,3],[4,5,6],[7,8,9]]
  • 複数行に複数の数値を取得して2次元配列に格納する(終了文字がある)
multiple_line_multiple_int3.hs
-- 終了文字列が存在する場合の2次元input
main :: IO ()
main = do
  intList2D <- map (map read . words) . lines <$> getContents :: IO [[Int]]
  -- すべてが0の行が出現するまで取得
  let result = takeWhile (not . all (== 0)) intList2D
  print result
# 終了文字列0が出るまで読み込む
cat <<'EOF' > input.txt
1 2 3
4 5 6
7 8 9
0 0 0
EOF
runghc multiple_line_multiple_int3.hs < input.txt && /usr/bin/rm input.txt
[[1,2,3],[4,5,6],[7,8,9]]
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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?