似非プログラマのうんちく

「似非プログラマの覚え書き」出張版

Ruby で FizzBuzz を満喫する

Scala にだいぶSAN値を削られたのでここいらで Ruby に日和ろう(苦笑)。

その 1 : Object#tap を利用する

to_fizzbuzz = -> n {
  "".tap do |_|
    _ << "Fizz" if n % 3 == 0
    _ << "Buzz" if n % 5 == 0
    break n if _.empty?
  end
}

puts 1.upto(100).map(&to_fizzbuzz)

RubyObject#tap はブロック内で自分自身に対して行われた破壊的変更が保証される。break が発動するとそれらの変更を破棄して強制的に別の値を返すことが出来る。発動しなければブロック内で行われた破壊的変更を適用した自身が返ることになる。

さくっと lambda 奴を使っておくと Enumerable#mapProc オブジェクトを渡す Ruby らしい書き方で処理が記述できる。

その 2 : Hash を利用する

Scala 編で Map を使ったやつの元ネタ。

Applicators = {3 => :Fizz, 5 => :Buzz}

to_fizzbuzz = -> n {
  fb = Applicators.select{|_| n % _ == 0}.values.join
  fb.empty? ? n : fb
}

puts 1.upto(100).map(&to_fizzbuzz)

やってることはほぼ一緒。メソッド名が違うだけ。

その 3 : Enumerable#zip を利用する

fizz = [nil] * 2 << :Fizz
buzz = [nil] * 4 << :Buzz

1.upto(100).zip(fizz.cycle, buzz.cycle) do |n, *f|
  puts f.any? ? f.join : n
end

ネットで見つけてきた。nilany の使い方が Ruby っぽくてお気に入りである。

続きを読む

Scala でとことん FizzBuzz する(その 3)

さぁ、改造を続けよう。

FizzBuzz アルゴリズム再考

ちょっとひねって、次のような写像を考える。

何も書いていないところは空文字列を対応させていると考える。これを利用して、FizzBuzzアルゴリズムを少し変更する。

  1. 何らかの方法で "", "", "Fizz", "", "Buzz", "Fizz", "", "", "Fizz", "Buzz", "", "Fizz", "", "", "FizzBuzz", ... と繰り返される列を用意する。
  2. 1 から順に上記の列と対応させていく(zip)
  3. 上記で得られた列を順に処理していくとき、「数字と空文字列」の組み合わせのときは数字を、「数字と空でない文字列」の組み合わせのときは文字列を返すようにする。

これを Scalaトレイトを利用して抽象クラスとしてあらかじめ作っておく。

package jp.mydns.akanekodou.scala.fizzbuzz

abstract class FizzBuzz {
  protected val fb : Stream[String]

  def fizzbuzz : Unit = {
    1 to 100 zip fb map {
      case (n, "") => n
      case (_, s) => s
    } foreach println
  }
}

Java のインターフェースと違い、Scala のトレイトにはこうした共通処理をあらかじめ実装しておくことが出来る。今回、ついでなので表示するところまでまとめて実装してみた。

2015/04/12 追記 : 今回のケースではトレイトを使う必要はありませんでした。お詫びの上、通常の抽象クラスに訂正させていただきます。

もう一つ、Scala の機能である「暗黙引数」を利用している。一見するとメソッドの引数のデフォルト値をあらかじめ与えるのと似ているが、あちらはあらかじめ引数を初期化しておかないとダメなのに対し、こちらはメソッド呼び出し時までに暗黙引数を初期化・確定させておけば良い。

Java の抽象クラスは「抽象メソッドが含まれるクラス」であるが、Scala の場合は抽象メソッドに加えて上記のような抽象フィールドを含むクラスも抽象クラスとして定義しなければならない。

2015/04/12 追記 2 : MainFizzBuzz 系クラスを継承させる方法が何となく行儀が悪く見えたので止めました。

その他のファイルも適宜書き換えていこう。

package jp.mydns.akanekodou.scala.fizzbuzz

class FirstFizzBuzz extends FizzBuzz {
  def toFizzBuzz(n : Int) : String = {
    if (n % 3 == 0) {
      if (n % 5 == 0)
        "FizzBuzz"
      else
        "Fizz"
    } else if (n % 5 == 0) {
      "Buzz"
    } else {
      ""
    }
  }

  val fb = Stream.from(1).map(toFizzBuzz)
}

toFizzBuzz は最早 String 型しか返さないことが明白になった。

package jp.mydns.akanekodou.scala

import jp.mydns.akanekodou.scala.fizzbuzz._

object Main extends App {
  (new FirstFizzBuzz).fizzbuzz
}

Main.scala がだいぶすっきりした。

いよいよ本格的に改造していくぞ !

続きを読む

Scala でとことん FizzBuzz する(その 2)

前回のプログラムは無事動いたかな ? では改造を始める。でもその前に…。

SBT で作ったプロジェクトを Scala IDE for Eclipse で扱えるようにする

前回までの手順で、プロジェクト直下に project フォルダが出来ていると思う。そこに plugins.sbt というファイルを以下の内容で作成する。

addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.5.0")

そうしたらプロジェクト直下で

> sbt eclipse

を実行する。これにより Eclipse 用の設定ファイルなどが作られ、Scala IDE for Eclipse でプロジェクトをインポートして扱うことが出来る。コーディング作業は IDE を使う方が楽なのでやっておくと良い。なお、SBT でライブラリの依存関係を変更したときは再度上記コマンドを実行しないと Eclipse 側に反映されないので注意。

続きを読む

Scala でとことん FizzBuzz する(その 1)

プログラミングをこよなく愛する皆さん、今日も元気に FizzBuzz してますか !

FizzBuzz って何 ?」という人から「FizzBuzz が何の役に立つんだよ」という人まで、今回は存分に FizzBuzz を楽しめる(?)連載を始めますよ !

FizzBuzz」とは何か

FizzBuzz。それはもっぱら英語圏で行われるちょっとしたレクリエーションのようなものである。数人が輪になって、最初の人から順々に数字を 1 から順に 100 まで言っていくのであるが、

  • 数字が 3 の倍数(3, 6, ...)のときは数字を言う代わりに「Fizz」と言う
  • 数字が 5 の倍数(5, 10, ..)のときは数字を言う代わりに「Buzz」と言う
  • 上記の両方に当てはまるとき、つまり数字が 15 の倍数(15, 30, ...)のときは数字を言ったり「Fizz」や「Buzz」と言う代わりに「FizzBuzz」と言う
  • それ以外のときは普通に数字を言う

という遊びである。これをプログラミングでやるときは、1 から 100 まで出力させ、その際に数字が 3 の倍数だったり 5 の倍数だったりするときにその出力を上記の文字列で置き換えて表示させるプログラムを組むことを FizzBuzz と言っている。

何故 FizzBuzz なのか

何故 FizzBuzz をプログラミングすることがそんなに大事なのかというと

  • 入出力
  • 反復
  • 条件分岐

の要素に習熟することに大変優れているから、というのが通説のようである。とりわけ反復と条件分岐が強調されることが多い。入出力は、いわゆる標準入出力はもちろんだが、広く「関数の in と out の関係」についても学ぶことが出来る。

参考 : 最終鬼畜FizzBuzz大全 - Qiita

原始 FizzBuzz

今回は Scala による FizzBuzz の様々な実装を考えてみることにする。まず最も素朴な FizzBuzz はこうなるだろう。

package jp.mydns.akanekodou.scala

object Main {
  def main(args : Array[String]) : Unit = {
    for (n <- 1 to 100) {
      if (n % 3 == 0) {
        if (n % 5 == 0)
          println("FizzBuzz")
        else
          println("Fizz")
      } else if (n % 5 == 0) {
        println("Buzz")
      } else {
        println(n)
      }
    }
  }
}

我々はこのソースコードからスタートして、さまざまな改造をしていくことになる。

SBT(Simple Build Tool)の導入

Scala プログラミングにおけるビルドツールの定番とされているのが SBT である。今回はこいつを使ってプロジェクトを作り、管理していく。Windows であれば MSI 形式のインストーラが配布されているのでインストールは難しくない。

プロジェクトの作成

まずプロジェクトのルートとなるディレクトリを作る。その中に build.sbt というファイル名で SBT 用の設定ファイルを作る。中身はこんな感じ。

name := "FizzBuzz"

version := "1.0"

scalaVersion := "2.11.6"

空行は省略できない。次にソースファイルを配置するフォルダの作成。プロジェクトルートで

> mkdir src\main\scala\jp\mydns\akanekodou\scala

作ったフォルダに先ほどのソースコードMain.scala というファイル名で保存し配置する。

プロジェクトのビルドと実行

プロジェクトルートで

> sbt

を実行する。初回起動時は必要なライブラリをダウンロードしてくるため時間が掛かる。気長に待とう。プロンプトが帰ってきたら

> compile
> run

コンパイル→実行できる。さて、意図した通りにプログラムは動いたかな ?

お詫びと補足

お詫び

昨日の記事ですが、IntStream の状態で一度 count をかますと、コメントに残していた一覧表示(forEach の部分)が不可能になります。お詫びして修正します。今回は個数だけを求めるプログラムに特化する形にさせていただきました。一覧も表示させる場合は、元のゆっちさんの書いたように、一度 boxed から collect して List 型にしておく必要があります。

補足

長くなるので折りたたむ。

続きを読む

エラトステネスの篩はもう古い !?

タイトルは親父ギャグじゃねーです !

ゆっちさんがこんな記事を書いていたようで。
ゆっちのBlog » Java8 時代の素数の求め方

最初はそのままパクらせていただいて動かしていました(それでもなかなかに早い)が、地味に無駄な処理があることに気がつきました。

boxed して collect してる部分がそれです。IntStream のままでも count メソッドで個数は確認できるので、以下のように修正してみました。あと、秒未満の処理時間は細かい数値はいらないと思ったのでミリ秒単位で切って表示させてます。


Stream API を用いた並列化された素数検出プログラム

実行時に他のプロセスが動いてたりするとアレですが、一応の目安として

1973815 個の素数を検出しました。
0 時間 0 分 32 秒 914

と、期待される結果と共に、家の非力なマシンでも 30 秒そこそこで処理が完了する*1ことがわかりました。Java8 すげぇ。

*1:オリジナル版だと 1 分ちょい掛かる