Unweave序列,Kotlinfunction/流式习语

我有一个交错的数据序列(与固定步幅),我想减少它为每个“结构”(n *跨度价值n值)单个值。

我可以使用循环写入到可变列表中,并为读者索引选定步骤,但是我正在寻找更多的function和可读的方法。 有什么想法吗?

例如:输入序列由RGB三元组(步幅3)组成,输出为灰度。

命令的方式是这样的:

fun greyscale(stream:List):List{ val out = ArrayList(stream.size / 3) var i = 0; var o = 0 while(i < stream.size) out[o++]=(stream[i++] + stream[i++] + stream[i++])/3 return out } 

我怎么能没有明确地实现一个函数和可变容器,而是纯粹的function扩展如.map等?

一种可能的方法是按元素的索引(在本例中为/3 )进行分组,并将这些组映射到它们的总和。

 stream.withIndex() .groupBy { it.index / 3 } .toSortedMap() .values .map { (it.sumBy { it.value } / 3).toByte() } 

同样严格的function,但使用Rx,将可能通过使用window(long)

 Observable.from(stream) .window(3) .concatMap { it.reduce(Int::plus).toObservable() } .map { (it / 3).toByte() } 

科特林1.2(里程碑1昨天发布)带来了分类方法集合。 它将收集块分成一定大小的块。 你可以用它来实现你的function:

 fun greyscale(stream: List): List = stream.chunked(3) .map { (it.sum() / 3).toByte() } 

排除其余元素:

 const val N = 3 fun greyscale(stream: List) = (0 until stream.size / N) .map { it * N } .map { stream.subList(it, it + N).sum() / N } .map(Int::toByte) 

产量

[1,2,3,4,5,6] => [2,5]

[1,2,3,4,5] => [2]

包括其余的元素:

 const val N = 3 fun greyscale(stream: List) = (0 until (stream.size + N - 1) / N) .map { it * N } .map { stream.subList(it, minOf(stream.size, it + N)).sum() / N } .map(Int::toByte) 

产量

[1,2,3,4,5,6] => [2,5]

[1,2,3,4,5] => [2,3]

最好的是我的能力是这样的:

 fun grayscale(rgb:List):List = rgb.foldIndexed( IntArray(rgb.size / 3), { idx, acc, i -> acc[idx / 3] = acc[idx / 3] + i; acc }).map{ (it / 3).toByte() } 

产量

在:[1,2,3,4,5,6]

出:[2,5]

ArrayList addlast变种

类似于@ marstran的答案,在Kotlin 1.2中,您可以使用chunked函数,但将变换lambda提供给它:

 fun greyscale(stream: List): List = stream.chunked(3) { it.average().toByte() } 

这个变体有一个好处,就是它不会为每个三元组实例化一个新的List,而是创建一个List并在整个操作中重用它。