saruboの書き溜め

いいこと書けないですけどこんな記事でよければ見ていってね

Scala の ArrayBuffer では init だけでなく dropRightInPlace を使うことも検討してみませんか?

主張

タイトル通り。ScalaArrayBuffer では init だけでなく dropRightInPlace を使うことも検討してみませんか?元の ArrayBuffer のデータを使わないという条件は付きますが dropRightInPlace の方が高速です。

val filled = ArrayBuffer.fill(1000000)(1)
assert(filled.init.length == 999999)
val filled = ArrayBuffer.fill(1000000)(1)
assert(filled.dropRightInPlace(1).length == 999999)

蛇足

Scalaを触っていると、List では ::、他のコレクションでも +:, :+ を使うことが多いです。その影響もあって head に対して tail, init に対して last を意識することも多いと思います。

そんなノリで foldLeft 中で ArrayBuffer から init を使っていたら、動かしてみたときになぜか遅くて頭を抱えてしまいました。

不思議に思っていたところ init がcopyを作成していることに気が付きました。気付いてしまえば当然ですよね。

Rust言語の Vecpop のように最後の要素をmutableに削除すればcopyを作成せずに高速に動作するはずなのですが、pop なんてmethodは見当たりませんでした。

頭を捻っていたところ、それっぽいmethodに trimEnd がありました。打ち込んでみると "use dropRightInPlace instead" と怒られました。 dropRightInPlace の実装を見てみると、こいつだぁ!となったので使用してみたところ、期待通りの速度が出ました。嬉しい。

自分としては pop みたいな、要素を 一つだけ 削除する高速なmethodが、mutableな ArrrayBuffer にはあればもっとサクッと書けたのにと思うばかりです。……実はあったりするんですかね?