🤔

『N個の値を入力するプログラム』が意外とめんどくさい

2020/11/14に公開約4,100字6件のコメント

【2021/10/27追記】本記事のテーマについては,次のpaizaのページが参考となるかもしれません.値取得・出力サンプルコード:https://paiza.jp/guide/samplecode

いやもう,FizzBuzz問題の代わりに『コードが書けないプログラマ志願者を見分ける手法』にしてもいいほどに(それは言い過ぎ).

以前,『サンプルコードは入力と出力をセットにして作成してから実行を確かめる』といったことを述べている記事を書き,また,その趣旨に基づく『最初のサンプルプログラム』集みたいな記事も作成しました.これらを踏まえ,AtCoderあたりでは定番の,値入力部分のサンプルプログラムをいろんな言語で書き始めてみたのですが…いやあ,めんどくさい.入力スタイルに合わせるのはもちろん,言語固有の工夫が必要だったり,入力後の処理によってケースバイケースとなったり."Hello, World!"プログラムが出力だけのことはあるといいますか.

とりあえず,次の競プロ練習風問題に対応するプログラムを,いくつかのプログラミング言語で書いてみた結果を掲載.必要に応じて追加・修正していく予定.『この言語ならもっとスマートに書けるぜ!』的なツッコミ・議論歓迎.

  • N個の整数値を入力すると,カンマ+空白区切りで逆順に出力するプログラム
  • 個数Nおよび整数値は,いわゆる半角空白か改行で区切って入力
  • 出力時のカンマ+空白の空白も半角とし,最後の値は改行のみ

【入出力例】

入力例1
3
10 20 30
出力例1
30, 20, 10
入力例2
4 10 20
30 40
出力例2
40, 30, 20, 10

プログラム例

C言語 (GCC 8.3.0)

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
  int n, *a;

  scanf("%d", &n);
  a = (int *)malloc(sizeof(int) * n);
  for (int i = 0; i < n; i++) scanf("%d", &a[i]);
  for (int i = n; i > 1; i--) printf("%d, ", a[i - 1]);
  printf("%d\n", a[0]);

  free(a);

  return 0;
}

C++ (GCC 8.3.0)

#include <iostream>
#include <string>
using namespace std;

int main(void)
{
  int n;

  cin >> n;
  string a[n];
  for (int i = 0; i < n; i++) cin >> a[i];
  for (int i = n; i > 1; i--) cout << a[i - 1] << ", ";
  cout << a[0] << "\n";

  return 0;
}

Lua (Lua 5.3.3)

n = io.read("n")
a = {}
for i = 1, n do a[#a+1] = io.read("n") end
for i = n, 2, -1 do io.write(a[i], ", ") end
io.write(a[1], "\n")

Scheme (GNU Guile 3.0.4およびGauche 0.9.9)

(define (readn n)
  (if (= n 0) '()
      (let ((r (read)))
        (cons r (readn (- n 1))))))

(let ((a (readn (read))))
  (for-each
    (lambda (x) (display x) (display ", "))
    (reverse (cdr a)))
  (display (car a)) (newline))

Common Lisp (SBCL 1.4.16)

(let* ((n (read))
       (a (mapcar #'read
            (coerce
              (make-array n :initial-element nil)
              'list))))
  (mapc
    (lambda (x) (princ x) (princ ", "))
    (reverse (cdr a)))
  (princ (car a)))

Python (Python 3.8.5)

i = input()
while i == '': i = input()

a = i.split()
n = int(a.pop(0))

while len(a) < n:
    i = input()
    while i == '': i = input()
    a = a + i.split()

for v in a[1:n][::-1]:
    print(v, ", ", end="")
print(a[0])

Python (Python 3.8.5)(別解)

a = input().rstrip().split(' ')
n, a = int(a[0]), a[1:]
while len(a) < n: a += input().rstrip().split(' ')
for i in range(n-1): print(a[n-i-1], end=', ')
print(a[0])

JavaScript (Node.js v10.24.0 + readline)

const rl = require('readline');
const std = {
  input:  process.stdin,
  output: process.stdout
};
const io = rl.createInterface(std);

let lines = [];
io.on('line', (x)=>lines.push(x));

function rlout() {
  const a = lines[0].split(" ");
  const n = a[0];
  let a1 = a.slice(1), i = 1;
  while (a1.length < n) {
    a1 = a1.concat(lines[i].split(" "));
    i++;
  }
  for (let i = n-1; i >= 0; i--) {
    process.stdout.write(a1[i]);
    if (i != 0)
      process.stdout.write(", ");
    else console.log();
  }
}
io.on('close', rlout);

Java (OpenJDK 11.0.12)

import java.util.Scanner;

public class ScannerSample {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int[] a = new int[n];
    for (int i = 0; i < n; i++) a[i] = sc.nextInt();

    for (int i = n; i > 1; i--) {
      System.out.print(a[i-1]);
      System.out.print(", ");
    }
    System.out.println(a[0]);
  }
}

備考

記事に関する補足

  • ちなみにこれ,『N個の(空白・改行区切りの)文字列』だともっとめんどくさい. もはや字句解析レベルの前処理が必要.空行で入力終わり,とするならsplit系でいけるのだけれども. Python版を見る限り,そこまでではなさそう.やっぱりめんどくさいけど.

更新履歴

  • 2021-11-11: JavaScript版(Node.js+readline),Java版を追加
  • 2021-11-08: Python版に別解を追加
  • 2021-10-27:冒頭にpaizaページを追記
  • 2020-11-16:Python版を追加
  • 2020-11-15:Scheme版を修正(Twitterコメントより)
  • 2020-11-14:初版公開

Discussion

value_list = list(map(int, input().split()))
n = value_list.pop(0)

while len(value_list) < n:
    value_list += list(map(int, input().split()))

for value in value_list[1:n][::-1]:
    print(value, ", ", end='')
print(value_list[0])

Pythonのところで、複数値入力のところはmapを使ってよしなにすると良い感じかもしれません

ありがとうございます.なるほど,input()の方ではなくint()map適用するとすっきりしますね.あれ,ってことは,リスト内包表記でも似たようなことができますね.ふむ.

a = [int(x) for x in input().split()]
n = a.pop(0)

while len(a) < n:
    a += [int (x) for x in input().split()]

for v in a[1:n][::-1]:
    print(v, ", ", end="")
print(a[0])

Rubyの場合ですと、入力例1は以下でどうでしょうか?
gets;puts gets.split.map(&:to_i).reverse.join(", ")

Python3にも挑戦してみました。入力例1の場合、以下でどうでしょうか?
input();print(", ".join(input().split()[::-1]))

返信ありがとうございます.あー,すみません,今回は入力例1と入力例2のどちらも受け付ける同じプログラムを想定してます.しかも,最初の整数の数の分しか逆順に表示しないという….あ,これでいけるかな?最初の整数より後が整数じゃなくなるけど.

a = input().split()
n = int(a.pop(0))
while len(a) < n: a += input().split()
print(", ".join(a[0:n][::-1]))

なるほど、入力例2も満たさなければならなかったんですね。

読み間違えてしまいました…

ログインするとコメントできます