在像scala这样的函数编程语言中,停止对集合进行迭代的方法是什么?例如;如果给定值中有0,则返回true。
给定数组的大小可以是100,其中0作为第一个元素。如何在scala中使用纯FP实现这一点?
对于命令式方法,通常是if(检查终止条件(后面加一个break来停止迭代。
我是FP&scala。有人能帮忙澄清吗?
如果您查看List
s、Set
s、Vector
s、Map
s等的API,您会看到许多实用程序,如:reduce
、fold
、foldLeft
、foldRight
、map
等。
大多数函数都假定您只能在遍历整个集合后返回结果。某些处理仅直到满足条件(例如.takeWhile(cond)
(,或者仅取满足条件(如find(condition)
(的特定示例。经常发生的情况是,你试图用一个循环做的是几个更简单的函数的组合,例如
var index = 0;
var result = 0;
// add all elements until first element bigger than 100
while (index < list.size) {
if (list(index) > 100)
break;
index++;
result += list(index);
}
可以在功能上表示为:
list.takeWhile(i => i > 100).sum
随着你学习和使用越来越多的这些方法,表达越来越复杂逻辑的能力将会提高。如果您不介意在整个集合中进行迭代,fold
、reduce
等通常允许您随心所欲地处理数据。
然而,如果你仍然不知道如何实现某个东西,因为你必须过滤、组合并决定停止迭代以避免noop循环,你总是可以恢复到尾部递归调用:
@scala.annotation.tailrec // annotation ensured that compiler will optimize body
def myOperation(unprocessedData: List[Int], resultSoFar: Int): Int =
unprocessedData match {
case head :: tail =>
val newResult = resultSoFar + head
myOperation(tail, newResult) // to enable tailrec instead of backtracking
// you pass partial results as argument
// and compiler will rewrite it underneath
// into while with break
case Nil =>
resultSoFar // final result
}
TL;博士
- 尝试使用内置函数
.map
、.collect
、.filter
、.drop
、.dropWhile
、.take
、.takeWhile
来构建您需要的内容 - 如果太难,请尝试使用
fold
、foldLeft
、foldRight
、reduce
- 如果仍然很困难,请尝试使用尾部递归-这基本上是
while
-break
的更安全版本,因此使用该版本,yo应该能够始终实现您想要的内容
您可以使用exists
有许多类型的不可变集合,它们不会从共同的祖先继承exists
,但您会通过不同的方式找到它。
这样的assert(List(0,1).exists(_ == 0))
在引擎盖下就可以了:
override final def exists(p: A => Boolean): Boolean = {
var these: List[A] = this
while (!these.isEmpty) {
if (p(these.head)) return true
these = these.tail
}
false
}
或assert(scala.collection.immutable.ArraySeq(0,1).exists(_ == 0))
将调用:
def exists(p: A => Boolean): Boolean = {
var res = false
val it = iterator
while (!res && it.hasNext) res = p(it.next())
res
}