前回の続き(2014年1月6日の日記参照)です。
おさらいすると、Booleanのリストをビット列に見立てて、任意のビット数を上位ビット〜下位ビットにOR演算し、Intのリストとして返すという処理をします。
ビット列 (0, 1, 0, 0, 1, 1, 0, 0, 0) に対して、(1ビット取る, 3ビット取る, 5ビット取る) という処理を行って、結果として (0, 4, 24) が返るイメージです。
(入力1)
List(
true, false, false, true, true, false, true, false,
true, true, true, false, true, false, true, true
)
(入力2)
List(1, 2, 3, 4, 5, 6)
(出力)
List(1, 0, 6, 11, 21)
ビット列に相当するリストが入力1、何ビットずつまとめるか、という別のリストが入力2になります。
前回は特に触れませんでしたが、入力1と入力2の合計が異なるときの扱いについては悩みどころです。余ったリストを返すのが一番親切かもしれませんが、出力が3つになってしまいます…。
今回は、一番楽に(入力1>入力2)なら例外スロー、(入力1<入力2)なら切り捨て、としています。
前回使ったmapでは(入力:出力)の要素数を(1:1)にする必要があります。そのため(n:1)にしたければ、入力はあるが、出力はない「穴が空いた」状態を表現する必要が生じます。
Option型を使って、値はSome(値), 穴はNoneとし、最後にflattenを呼んでNoneを全部捨てましたが、あまり効率的とは思えません。
入出力の要素数が一致していなくても構わないのがfoldLeftです。
object BooleanToInt {
def apply(g: List[Int]): ((List[Int], Boolean) => List[Int]) = {
val o = new BooleanToInt(g)
o.folder
}
}
class BooleanToInt(g: List[Int]) {
private var v = 0
private var p = 0
private var mp = g(0)
private var gg = g.drop(1)
def folder(a: List[Int], b: Boolean): List[Int] = {
v <<= 1
if (b) v |= 1
p += 1
if (p >= mp) {
val result = a :+ v
v = 0
p = 0
mp = gg(0)
gg = gg.drop(1)
result
} else {
a
}
}
}
val a = List(
true, false, true, false,
true, true, false, false,
true, false, false, true,
false, true, true, false
)
val b = List(1, 2, 3, 4, 5, 6)
val c = a.foldLeft(List[Int]())(BooleanToInt(b))
println(c)
コードがScala素人くさいのはさておき、SomeとかNoneが出てこない分、mapより良さそうです。
val c = (List[Int]() /: a)(BooleanToInt(b))
初期値のリストが長いときはfoldLeftを /: で書く手もあります。個人的には右側が被演算子になると読みづらいし、使うことはないですね…。
< | 2014 | > | ||||
<< | < | 01 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | - |
合計:
本日:
管理者: Katsuhiro Suzuki(katsuhiro( a t )katsuster.net)
This is Simple Diary 1.0
Copyright(C) Katsuhiro Suzuki 2006-2023.
Powered by PHP 8.2.15.
using GD bundled (2.1.0 compatible)(png support.)