简体   繁体   中英

Scala: fold over two-dimensional array

Given a potentially large image (or two-dimensional array of numbers), I'd like to loop over all the pixels (or numbers) and eg count all the black ones (or 0 values).

I know I can simply use a for comprehension like

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

but then I need a mutable variable for the count. Which may not really be a problem, but suppose I don't want this and would like to use a more functional style, how do I do this without creating a large data structure with width x height elements (in other words keeping the memory-efficiency of the 0 until img.height and 0 until img.width ranges)?

Map over the collection, transforming inner ones into subcounts, and then sum those :

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

EDIT

You can create a Stream using

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

and then use

stream.count(isBlack)

Note that Stream.tabulate accepts up to 5 dimensions (as its first argument).

You can use for comprehension with ranges to convert an image to a sequence of pixels:

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

But this will create a full sequence in memory. To make it lazy you may take views of the ranges:

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

With that you may call higher-level functions on this sequence to calculate what you need:

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

You may, of course, add this conversion to a pixel sequence as an implicit method of your image 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)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM