標準入力から数値列を読み込んで、逆順に標準出力に吐き出す
手元にある各言語で、標準入力から数値列を読み込んで、逆順にしたうえで標準出力に吐き出すプログラムを書いてみようと思ったメモ。
標準入力から入力される数値列の要件は以下の通り。
- 1行に1つの数値が書かれている
- 不正入力のチェックは不要とする
- いくつの数値が入力されるかは不明(ただし、メモリがあふれることが無い程度に手加減する)
- 入力される数値は符号付32ビット整数とする
入力される数値の上限数設定が無いことで、前々回、前回のように配列を静的に準備しておくということができないので、真面目に動的な配列あるいはリスト構造を考えないといけなくなるところがポイント。
環境
手元にあるものということで、環境は以下のものに限定する。
- CentOS 7
入力ファイルの例
- 001.txt
0 1 -1 256 -256 32768 -32768 2147483647 -2147483648
期待される出力の例
- 001.txt
-2147483648 2147483647 -32768 32768 -256 256 -1 1 0
Java
import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Scanner; public class Main { public static void main(String[] args) { try (Scanner in = new Scanner(System.in); PrintWriter out = new PrintWriter(System.out) ) { List<Integer> list = new ArrayList<>(); while (in.hasNextInt()) { list.add(in.nextInt()); } Collections.reverse(list); for (Integer num : list) { out.println(num); } } } }
Javaの場合、Listの要素を逆順にするメソッドがCollections
クラスに用意されているので、それを使えば一発。
C
#include <stdio.h> #include <stdlib.h> struct _IntNode { int value; struct _IntNode* prev; struct _IntNode* next; }; typedef struct _IntNode IntNode; typedef struct { int size; IntNode* first; IntNode* last; } IntList; IntList* IntList_new() { IntList* list = (IntList*)calloc(sizeof(IntList), 1); list->first = NULL; list->last = NULL; list->size = 0; return list; } void IntList_destroy(IntList* list) { IntNode* node = list->first; while (node != NULL) { IntNode* next = node->next; free(node); node = next; } free(list); } void IntList_add(IntList* list, int value) { IntNode* node = (IntNode*)calloc(sizeof(IntNode), 1); node->next = NULL; if (list->last != NULL) { list->last->next = node; node->prev = list->last; } else { list->first = node; node->prev = NULL; } list->size++; list->last = node; node->value = value; } void IntList_reverse(IntList* list) { int left = 0; int right = list->size - 1; IntNode* leftNode = list->first; IntNode* rightNode = list->last; while (left < right) { int tmp = leftNode->value; leftNode->value = rightNode->value; rightNode->value = tmp; ++left; --right; leftNode = leftNode->next; rightNode = rightNode->prev; } } int main(int argc, char** argv) { IntList* list = IntList_new(); int num; while (scanf("%ld", &num) == 1) { IntList_add(list, num); } IntList_reverse(list); for (IntNode* node = list->first; node != NULL; node = node->next) { printf("%d\n", node->value); } IntList_destroy(list); return 0; }
C言語にはリスト構造がそもそも無いので、そこの実装から。今回はlinked listで実装したが、Javaで言うところのArrayList
方式の実装も考えられる。今回は面倒だったので止めたが。
逆順にする処理は、実装したlinked listに対して愚直に各要素の値を入れ替える処理。
C++
#include <algorithm> #include <iostream> #include <vector> using namespace std; void reverse_vector(vector<int>& list) { for (int left = 0, right = list.size() - 1; left < right; ++left, --right) { int tmp = list[left]; list[left] = list[right]; list[right] = tmp; } } int main(int argc, char** argv) { vector<int> list; int num; while (cin >> num) { list.push_back(num); } reverse_vector(list); for (int i = 0; i < list.size(); ++i) { cout << list[i] << endl; } return EXIT_SUCCESS; }
逆順にする処理は、愚直に各要素の値を入れ替える処理。
PHP
<?php $lines = file('php://stdin'); $ary = array(); foreach ($lines as $line) { $ary[] = (int)$line; } $left = 0; $right = count($ary) - 1; while ($left < $right) { $tmp = $ary[$left]; $ary[$left] = $ary[$right]; $ary[$right] = $tmp; ++$left; --$right; } foreach ($ary as $num) { printf("%d\n", $num); }
逆順にする処理は、愚直に各要素の値を入れ替える処理。
Python 2
import sys list = [] while True: line = sys.stdin.readline() if line == '': break list.append(int(line)) list.reverse() for num in list: print num
逆順にする処理は、reverse
メソッドで一発。
Python 3
import sys list = [] while True: line = sys.stdin.readline() if line == '': break list.append(int(line)) list.reverse() for num in list: print(num)
逆順にする処理は、reverse
メソッドで一発。
Ruby
list = [] while line = STDIN.gets num = line.to_i list.push(num) end list = list.reverse() for num in list print num,"\n" end
逆順にする処理は、reverse
メソッドで一発。
Perl
my $line; my @list = (); my $count = 0; while ($line = readline(STDIN)) { my $num = $line + 0; $list[$count] = $num; ++$count; } @list = reverse @list; for (my $i = 0; $i < $count; ++$i) { print "$list[$i]\n"; }
逆順にする処理は、reverse
関数で一発。
Go
package main import ( "bufio" "fmt" "io" "os" "strconv" "container/list" ) func main() { l := list.New() stdin := bufio.NewReader(os.Stdin) buf := make([]byte, 0, 1024) for { line, prefix, err := stdin.ReadLine() if err == io.EOF { break } buf = append(buf, line...) if prefix { continue } s := string(buf) num, err2 := strconv.Atoi(s) if err2 != nil { panic(err2) } l.PushBack(num) buf = make([]byte, 0, 1024) } l2 := list.New() for elem := l.Back(); elem != nil; elem = elem.Prev() { l2.PushBack(elem.Value) } l = l2 for elem := l.Front(); elem != nil; elem = elem.Next() { fmt.Println(elem.Value) } }
初めてlistコンテナを使ってみた。
逆順にする処理は、元のリストを末尾から捜査して別のリストに放り込むことで実現。
そもそも、入力処理の際にlist.PushFront()
すればいいという話もあるが、それはそれとして(ぉ。
bash
#! /bin/bash nl -ba | sort -nr | cut -f 2
nl
コマンドで行番号を付けて、行番号で逆順ソートして、行番号をカットする、という単純な処理。