我有一个2D IntArray
代表一个游戏板,其中-1表示空格,而某些值更大或等于0意味着该单元属于某个玩家。像下面的东西(-1用点(。)表示)
. . . . .
1 0 . . 2
0 . 1 3 3
4 3 . . 0
我希望获得一个Set
,其中包含已被任何玩家占用的单元格位置。像这样:
[Cell{1,0}, Cell{1,1}, ..., Cell{3,4}]
我知道第一种方法是迭代2D数组:
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))
}
}
但是......如果我使用流,它会以某种方式提高效率吗?它可以用更少的代码和更有效的方式实现吗?
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())
答案 0 :(得分:1)
如果Java流被范围替换,可以使Kotlin更自然。
val cells = (0 until board.size).flatMap { row ->
(0 until board[row].size)
.filter { col -> board[row][col] >= 0 }.map { Cell(row, it) }
}.toSet()
答案 1 :(得分:1)
首先,建议使用Kotlin标准库而不是Java流。使用Kotlin标准库s1m0nw1 gave a good solution,我只会将flatMap
替换为flatMapTo
,以避免创建后来被丢弃的列表:
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)
}
}
如果您确实需要Java8流解决方案,请使用以下代码:
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())
在性能方面,这里给出的两个解决方案应该非常相似(尽管我还没有测试过)。但是,Java8流允许您并行执行操作(请参阅StreamSupport.stream
)。这是使用一些线程池,为您完成所有的魔术。据我所知,Kotlin并不提供开箱即用的任何并行操作,但它的Coroutines比Java线程快得多 - 但是你可以使用更多的代码。