在Kotlin中跳出无限循环的foreach

4

我需要为课程制作一个计算生日悖论的程序。现在,我在尝试学习Kotlin并且遇到了一小段代码的问题:

        val checkSet = mutableSetOf<Int>()
        generateSequence{ Random.nextInt(n)}.forEach {
            if(!checkSet.add(it)) {
                return@outForeach
            }
        }
        outForeach@
        sum += checkSet.size

正如你所看到的,我正在尝试使用一个无限序列来实现这个功能。但是 Kotlin 不接受此操作,因为 outForeach 是一个未解决的引用。但是下面这种方法也不起作用:

        val checkSet = mutableSetOf<Int>()
        generateSequence{ Random.nextInt(n)}.forEach {
            if(!checkSet.add(it)) {
                return@forEach
            }
        }
        sum += checkSet.size

这只会重新启动forEach循环。是否有一种方法可以实现类似于forEachUntil的东西?

附注:我意识到这看起来很像这个问题:'return' doesn't jump out of forEach in Kotlin,只是我不太理解答案,也不知道它是否适用于这里。此外,对我来说,实现forEachUntil的方式更加优雅。

2个回答

2

以下是与 first 相关的替代方案:

  • using a simple while without body:

    while (checkSet.add(Random.nextInt(n))); // <- that semicolon is required! otherwise you execute what is coming next within the while
    
  • using run with a label:

    run outForeach@{
      generateSequence{ Random.nextInt(n)}.forEach {
        if(!checkSet.add(it)) {
          return@outForeach
        }
      }
    }
    
  • maybe also takeWhile might be helpful. In this specific case however it is surely not (as it would check against the checkSet and leave us with a sequence that isn't consumed... but if the condition would be different, it may make sense to consider something like take, takeWhile, takeLast, etc.):

    generateSequence { Random.nextInt(n) }
        .takeWhile(checkSet::add) // as said: for this specific condition it doesn't make sense... 
        .forEach { /* do nothing except consume the sequence */ } // the same values you added to the set would be available in this step of course
    

while循环是更优雅的解决方案,因为它不会产生未使用的序列或引用。 - Dean
这是真的,虽然它在这个特定的例子中运行得相当不错,但在其他需要真正的返回的情况下可能不适用...(尽管我不知道有任何需要使用goto-label-construct的情况,而不能使用其他方法解决) - Roland

1

我想我自己找到了解决方案:

        val checkSet = mutableSetOf<Int>()
        generateSequence{ Random.nextInt(n)}.first { !checkSet.add(it) }
        sum += checkSet.size

基本上使用函数first(),并保持返回false,直到你想跳出循环。只需丢弃函数first()的返回值。


它说我可以在两天内完成这个任务。 - Typhaon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接