前書き
(1)の続き。
自分ルールの中で、慣れない言語に触れるときに必ずやっているのが、データドリブン的に「Map, Filter, Reduce」が素直に記述できるかを確かめること。
慣れない言語を触らなければならない時に「あれ、map, filter, reduceっぽいことどうやるんだっけ?」ってなった時のリファレンスになれば幸い。
実際にやってみた
処理概要
- 10,000,000件のデータを生成(整数値で0〜9,999,999の値が入っている)
- 各要素を2倍にする
- 3の倍数である数値のみ抽出
- 抽出後の要素を総和する
対象言語
- F# (4.1)
- Scala(v2.12.2)
環境
- MacBook Air (Early 2014)
- macOS Sierra 10.12.4
- Visual Studio Code (エディタ)
制限事項
- 言語特有の裏技を駆使して最速を目指すのは避けた(自分の中では普通に書いたつもり)
- 生成したデータはイテレータオブジェクトではなく、実体データの集合になるようにした
- map, filter, reduce処理呼び出しについては続けて呼ぶような記述にした
- 計算結果は全ての言語において
33333336666666
になっていることを確認済み - map処理の開始直前からreduce処理終了までの時間を参考までに計測した
コード
時間計測処理付きのコードはGitHubに上げており、各言語のフォルダにあるmapFilterReduce.*
ファイルを参照のこと。
F#
open System
let a =
// 1. Generating sequence
[|0L..10000000L|]
let result =
a
// 2. Mapping the sequence into another (Deferred execution)
|> Seq.map ((*) 2L)
// 3. Filtering the sequence (Deferred execution)
|> Seq.filter (fun n->n%3L=0L)
// 4. Reducing the sequence
|> Seq.fold (+) 0L
// As a result
printfn "%A" result
Scala
object MapFilterReduce extends App{
// 1. Generating sequence
val a = (0L to 9999999L).toArray
var result =
// 2. Mapping the sequence into another
a.map(_*2)
// 3. Filtering the sequence
.filter(_%3==0)
// 4. Reducing the sequence
.fold(0L)(_+_)
// As a result
println(result)
}
考察
- 今回の件を機に初めて触る言語も多いのだが、Map, Filter, Reduce以外にもArray生成方法とか処理時間計測の方法も副産物として覚えることができた
- F#はSeqモジュールを使っている関係上、遅延評価の部分がある。Scalaはまだ勉強開始したばかりなので機会があれば調べてみたい。
参考結果
計測値は揺らいでいたけど大体この前後ということで端数をカット。
言語 | 計測値(msec) | 備考 |
---|---|---|
F# | 400 | |
Scala | 550 | scalacオプションなしでコンパイル |