FizzBuzz を20言語で頑張って書いてみる。
概要
標準出力・ループ・分岐などの練習のためFizzBuzz 問題を各言語で書いてみる。
知っている人は多いとは思うが、念のためFizzBuzzとは何かを説明する。
を言い合うゲームであり、これをプログラムで標準出力する。
簡単のため、入力はなしとし 1〜100(固定)までの数で行う。<実行例>
$ ./fizzbuzz 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz (16 〜 84を省略) Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz
言語基準
使用頻度の高そうなもの(参照:TIOBE Index | TIOBE - The Software Quality Company)のうち、自身が興味あるものを使用。
[除外言語]
アセンブラ→ 命令以外にもアセンブラ処理の疑似命令があったり、CPUによっても命令セットが異なるため除外
Delphi→ 開発環境が高い、無料版は使用可能日数が少ないため除外
COBOL→ サンプルソースコード見て吐きそう気軽に書けそうになかったため除外
注意点
できる限り処理内容が同じになるようにしています。
条件に対する各処理が同じ概念なら、if文はできる限り中括弧外してます。(そっちの方が読みやすいと思っているので)
末尾の改行のあるなしは結構適当だったり・・・。最大限でないようにはしてるつもりですが。
C/C++
#include<stdio.h> int main() { int i; for(i=1; i<=100; i++) { char tmp[9] = {}; if (i % 3 == 0) sprintf(tmp, "Fizz"); if (i % 5 == 0) sprintf(tmp, "%sBuzz", tmp); if (!*tmp) sprintf(tmp, "%d", i); puts(tmp); } return 0; }
C#
LINQを使った実装。
using System; using System.Linq; namespace ConsoleApplication { class FizzBuzzMain { static void Main(string[] args) { Console.WriteLine(string.Join("\n", Enumerable.Range(1, 100).Select(FizzBuzz))); } static string FizzBuzz(int i) { string tmp = ""; if (i % 3 == 0) tmp = "Fizz"; if (i % 5 == 0) tmp += "Buzz"; return tmp.Length == 0 ? i.ToString() : tmp; } } }
D
import std.stdio; import std.conv; string fizzbuzz(int i) { auto tmp = ""; if (i % 3 == 0) tmp = "Fizz"; if (i % 5 == 0) tmp ~= "Buzz"; if (tmp.length == 0) tmp = to!string(i); return tmp; } void main() { foreach(i; 1..101) writeln(fizzbuzz(i)); }
Objective-C
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { NSMutableArray *list = [NSMutableArray array]; for (int i=1; i<=100; i++) { NSMutableString *tmp = [NSMutableString string]; if (i % 3 == 0) [tmp appendString:@"Fizz"]; if (i % 5 == 0) [tmp appendString:@"Buzz"]; [list addObject:([tmp length] ? tmp : [NSString stringWithFormat:@"%d", i])]; } printf("%s", [[list componentsJoinedByString:@"\n"] UTF8String]); } return 0; }
Swift
import Foundation func fizzbuzz(num: Int) -> String { if (num % 15 == 0) { return "FizzBuzz" }else if (num % 3 == 0) { return "Fizz" }else if (num % 5 == 0){ return "Buzz" }else { return num.description } } print(join("\n", (1 ... 100).map(fizzbuzz)))
Java
import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<String> list = new ArrayList<String>(); for (int i = 1; i <= 100; i++) { StringBuilder sb = new StringBuilder(); if (i % 3 == 0) sb.append("Fizz"); if (i % 5 == 0) sb.append("Buzz"); list.add(sb.length() == 0 ? String.valueOf(i) : sb.toString()); } System.out.print(list.stream().collect(Collectors.joining("\n"))); } }
Groovy
Rubyの影響を受けた言語らしくかなり似てる。関数言語で頻繁に使う map がcollectっていう名前だった。
def fizzbuzz(int num) { def tmp = "" if (num % 3 == 0) tmp = "Fizz" if (num % 5 == 0) tmp += "Buzz" return tmp.length() == 0 ? num.toString() : tmp } print((1..100).collect (this.&fizzbuzz).join("\n"))
Bash
IFSに改行セットするのに苦労。
#!/bin/bash list=() for i in {1..100}; do TMP="" if [ $(($i % 3)) -eq 0 ]; then TMP="Fizz" fi if [ $(($i % 5)) -eq 0 ]; then TMP=$TMP"Buzz" fi list[i-1]=${TMP:-$i} done IFS=$'\n' echo "${list[*]}"
Python
#!/usr/bin/python def fizzbuzz(num): tmp = "" if num % 3 == 0: tmp = "Fizz" if num % 5 == 0: tmp += "Buzz" return tmp if len(tmp) != 0 else str(num) list = [] for i in range(1, 101): list.append(fizzbuzz(i)) print("\n".join(list))
PHP
<?php $list = array(); for ($i=1; $i<=100; $i++) { $tmp = ""; if ($i % 3 == 0) { $tmp = "Fizz"; } if ($i % 5 == 0) { $tmp = $tmp . "Buzz"; } $list[] = empty($tmp) ? $i : $tmp; } echo implode("\n", $list);
Perl
#!/usr/bin/perl @list = (); foreach $i (1..100) { $tmp = ""; if ($i % 3 == 0) { $tmp .= "Fizz"; } if ($i % 5 == 0) { $tmp .= "Buzz"; } push(@list, length($tmp) ? $tmp : $i); } print(join("\n", @list));
Ruby
print (1..100).map { |i| tmp = "" tmp << "Fizz" if i % 3 == 0 tmp << "Buzz" if i % 5 == 0 tmp.empty? ? i.to_s : tmp }.join("\n")
JavaScript
var list = [] for(var i=1; i<=100; i++) { var tmp = ""; if (i % 3 == 0) tmp = "Fizz"; if (i % 5 == 0) tmp += "Buzz"; list.push(tmp.length == 0 ? i.toString() : tmp); } console.log(list.join("\n"));
Go
なんか色々用語が特殊だったり(なんだよSliceって!)、普通ある構文がなかったり(?:演算子)とちょっと苦労した。
package main import ( "fmt" "unicode/utf8" "strings" ) func main() { result := []string{} for i := 1; i <= 100; i++ { tmp := "" if i % 3 == 0 { tmp = "Fizz" } if i % 5 == 0 { tmp += "Buzz" } if utf8.RuneCountInString(tmp) == 0 { tmp = fmt.Sprintf("%d", i) } result = append(result, tmp) } fmt.Print(strings.Join(result, "\n")) }
Scala
joinがないと思ったらmkStringという珍しいメソッド名だった。
object Main { def fizzbuzz(n: Int): String = { if (n % 15 == 0) "FizzBuzz" else if (n % 3 == 0) "Fizz" else if (n % 5 == 0) "Buzz" else n.toString() } def main(args: Array[String]): Unit = { print((1 to 100).map(fizzbuzz).mkString("\n")) } }
Clojure
最初みたときは気持ち悪いと思ったけど、使ってみると意外と悪くない。
(ns fizzbuzz.core (:gen-class)) (defn- factor? [factor, n] (if (= (mod n factor) 0) true false)) (defn fizzbuzz [n] (cond (factor? 15 n) "FizzBuzz" (factor? 3 n) "Fizz" (factor? 5 n) "Buzz" :else (str n))) (defn -main [& args] (print (clojure.string/join "\n" (map fizzbuzz (range 1 101)))))
Haskell
import Data.List fizzbuzz :: (Show a, Integral a) => a -> String fizzbuzz x | isFactorOf 15 = "FizzBuzz" | isFactorOf 3 = "Fizz" | isFactorOf 5 = "Buzz" | otherwise = show(x) where isFactorOf y = x `mod` y == 0 main :: IO() main = putStrLn $ intercalate "\n" $ map fizzbuzz (take 100 [1..])
F#
let fizzbuzz num = let f n = num % n = 0 if f 15 then "FizzBuzz" else if f 3 then "Fizz" else if f 5 then "Buzz" else num.ToString() [<EntryPoint>] let main argv = printfn "%s" (String.concat "\n" (List.map fizzbuzz [1..100])) 0
VisualBasic/VB.NET
Module FizzBuzz Sub Main() Console.WriteLine(String.Join(vbCrLf, Enumerable.Range(1, 100).Select(AddressOf FizzBuzz))) End Sub Function FizzBuzz(i As Integer) Dim tmp = "" If i Mod 3 = 0 Then tmp += "Fizz" End If If i Mod 5 = 0 Then tmp += "Buzz" End If Return IIf(tmp.Length = 0, i.ToString(), tmp) End Function End Module
R
fizzbuzz <- function (n) { tmp <- "" if (n %% 3 == 0) tmp <- "Fizz" if (n %% 5 == 0) tmp <- paste0(tmp, "Buzz") if (nchar(tmp) == 0) tmp <- as.character(n) tmp } for(i in 1:100) print(fizzbuzz(i))
おわりに
各言語の特徴的な機能をなるべく用いて実装したつもりですが、経験のない言語が多く
この程度の内容でも全部書くのに4日かかりました。(今回のために改めて開発環境作ったものも多い)
やってみた感想として。
15言語目くらいで心が折れかけました。面白い処理書いているならいいんですが、
FizzBuzzのために、違う言語とはいえ、ひたすら同じ項目をネットで調べるのは精神衛生上あまり良くなかったです。
・・とはいえ、同じような作業やってて、いくつか気づきもありました。
近年流行の言語は関数型言語の影響を受けていて、その共通のメソッドがすでにライブラリとして実装されているため、
関数言語を一つやっていれば、簡単な処理くらいならすぐ書けそうってこと。
また、ある言語を使うときに影響を受けた言語を知っていると、どんなものが記述できそうか想像できるため学習コストが間違いなく減ります。
事実、Swift, F#, Groovy などは今回初コーディングですが、既に知っている言語に記述が似ていた事、IDEの補完機能のおかげもあり時間がほぼ掛かっていません。
こういう意味では、広く浅く言語の特徴を知っている事は今後のための投資ととらえれば悪い事ではないと思います。
今回は簡単なものとして FizzBuzz で記述したけど、記述方法の違い程度しか分からないものも多いので、
今後機会があれば、別バージョンやろうと思います。言語数は減らすと思いますが!