Scala:折叠二维数组

Scala: fold over two-dimensional array

给定一个可能很大的图像(或二维数字数组),我想遍历所有像素(或数字),例如计算所有黑色的(或 0 个值)。

我知道我可以简单地使用 for comprehension like

for (y <- 0 until img.height; x <- 0 until img.width) {
    ...
}

但是我需要一个可变变量来进行计数。这可能不是真正的问题,但假设我不想要这个并且想使用更实用的样式,我该怎么做而不创建具有宽度 x 高度元素的大型数据结构(换句话说保持内存 - 0 until img.height0 until img.width 范围的效率)?

映射集合,将内部的转化为子计数,然后对它们求和:

scala> val m = Array(
         Array("B","B","W"),
         Array("W","W","B"),
         Array("W","W","W")
       )
m: Array[Array[String]] = Array(Array(B, B, W), Array(W, W, B), Array(W, W, W))

scala> m.map(_.count(_ == "B")).sum
res0: Int = 3

编辑

您可以使用

创建Stream
Stream.tabulate(img.height, img.width)(identity)

然后使用

stream.count(isBlack)

请注意 Stream.tabulate 最多接受 5 个维度(作为其第一个参数)。

您可以使用 for comprehension with ranges 将图像转换为像素序列:

for {
    y <- 0 until img.height
    x <- 0 until img.width
} yield image(x, y)

但这会在内存中创建一个完整的序列。为了让它变得懒惰,您可以查看范围:

for {
    y <- (0 until img.height).view
    x <- (0 until img.width).view
} yield image(x, y)

有了它,您可以在此序列上调用更高级别的函数来计算您需要的内容:

(
    for {
        y <- (0 until img.height).view 
        x <- (0 until img.width).view
    } yield image(x, y)
).count(_.isBlack)

当然,您可以将此转换作为图像的隐式方法添加到像素序列中 class:

implicit class ImageOperations(image: Image) {
    def toPixelSeq = for {
        y <- (0 until img.height).view 
        x <- (0 until img.width).view
    } yield image(x, y)
}