Status Code 303 - See Other

サーバサイド、iOS・アンドロイドアプリ、インフラレベルの話まで幅広くやってます。情報の誤りや指摘・意見などは自由にどうぞ。

FizzBuzz を20言語で頑張って書いてみる。

概要

標準出力・ループ・分岐などの練習のためFizzBuzz 問題を各言語で書いてみる。
知っている人は多いとは思うが、念のためFizzBuzzとは何かを説明する。

  • 15の倍数なら「FizzBuzz
  • 3 の倍数なら「Fizz
  • 5 の倍数なら「Buzz」
  • それ以外は その数値

を言い合うゲームであり、これをプログラムで標準出力する。
簡単のため、入力はなしとし 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

C#版を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 で記述したけど、記述方法の違い程度しか分からないものも多いので、
今後機会があれば、別バージョンやろうと思います。言語数は減らすと思いますが!