Scala:折叠二维数组

时间:2015-02-18 13:30:32

标签: scala functional-programming

考虑到潜在的大图像(或二维数字数组),我想循环遍历所有像素(或数字),例如计算所有黑色(或0值)。

我知道我可以简单地使用像

这样的理解
for (y <- 0 until img.height; x <- 0 until img.width) {
    ...
}

然后我需要一个可变变量来计算。这可能不是一个真正的问题,但假设我不想要这个并且想要使用更多功能的样式,如何在不创建宽度为x高度元素的大型数据结构的情况下执行此操作(换句话说,保留内存 - 0 until img.height0 until img.width范围的效率?

2 个答案:

答案 0 :(得分:5)

映射集合,将内部变换为子集,然后对它们求和:

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个维度(作为其第一个参数)。

答案 1 :(得分:1)

您可以使用范围理解将图像转换为像素序列:

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)

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

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