Reputation: 150
I have a 2D IntArray
which represent a game board where -1 means a blank space, and some value grater or equals to 0 means that cell belongs to some player. Something like below (-1 are represented by dots(.))
. . . . .
1 0 . . 2
0 . 1 3 3
4 3 . . 0
I want to get a Set
with the location of cells already occupied by any player. Something like this:
[Cell{1,0}, Cell{1,1}, ..., Cell{3,4}]
I know the first approach would be iterate over the 2D array:
val set = HashSet<Cell>();
for(row in 0 until HEIGHT){
for (col in 0 until WIDTH){
if(board[row][col] >= 0)
set.add(Cell(row, col))
}
}
But... is it somehow more efficient if I use streams? could it be achieved in less code and more efficiently?
IntStream.range(0, HEIGHT)
.mapToObj { row -> IntStream.range(0, WIDTH)
.filter{ col -> board[row][col] >= 0}
.mapToObj { col -> Cell(row, col) } }
.flatMap { point -> point }
.collect(Collectors.toSet())
Upvotes: 2
Views: 1052
Reputation: 8390
First of all, it is recommended to use the Kotlin standard library and not Java streams. With the Kotlin standard library, s1m0nw1 gave a good solution where I'd only replace the flatMap
with a flatMapTo
call to avoid creating a list that is later discarded:
val set = HashSet<Cell>()
(0 until board.size).flatMapTo(set) { row ->
(0 until board[row].size).filter { col ->
board[row][col] >= 0
}.map { col ->
Cell(row, col)
}
}
If you really need a Java8 stream solution, go with the following code:
fun IntRange.stream() : Stream<Int>
= StreamSupport.stream(spliterator(), false)
val set = (0 until board.size).stream().flatMap { row ->
(0 until board[row].size).stream().filter { col ->
board[row][col] >= 0
}.map { col ->
Cell(row, col)
}
}.collect(Collectors.toSet())
As of performance, both solutions given here should be quite similar (I haven't tested it though). However, Java8 streams allow you do operations in parallel (see StreamSupport.stream
). This is using some thread pool that does all the magic for you. Kotlin, as far as I know, does not offer any parallel operations out of the box, but it has Coroutines that are a lot faster than Java threads - but come together with more code on your side.
Upvotes: 1
Reputation: 81989
This can be made a bit more Kotlin-natural if the Java streams are replaced by ranges.
val cells = (0 until board.size).flatMap { row ->
(0 until board[row].size)
.filter { col -> board[row][col] >= 0 }.map { Cell(row, it) }
}.toSet()
Upvotes: 1