his Coursera course倒数第二讲, 奥德斯基教授提供了以下 for
理解作为一个可爱案例研究的最后一步:
def solutions(target: Int): Stream[Path] =
for {
pathSet <- pathSets
path <- pathSet
if path.endState contains target
} yield path
在较早的讲座中,他在
for
之间做了一些类比。理解和 SQL。我正在寻找的方法是
yield
只有那些 path
具有 DISTINCT
的 s endState
.有没有办法从具有相同理解的过滤器子句中引用已经产生的项目?
另一种方法可能是转换
pathSets
到 Map
来自 endState
至path
在 for
之前语句,然后将其转换回 Stream
在返回之前。然而,这似乎失去了使用 Stream
的惰性计算优势。 .来自同一案例研究的早期方法实现了类似的目标,但它已经是一个递归函数,而这个(似乎)不需要递归。
看起来我可以使用可变的
Set
跟踪 endState
s 得到了让步,但感觉并不令人满意,因为到目前为止,该类(class)已成功避免使用可变性。
最佳答案
Is there a way to refer back from within a filter clause of the same comprehension to the items that have already been yielded?
你的理解对某些东西或多或少像
pathSets flatMap {
pathSet => pathSet filter {
path => path.endState contains target
}
} map {path => path}
最后一张带有恒等函数的 map 是你的产量。我不记得当它是一个身份函数时,规范是否允许省略该映射。
无论如何,我希望这能更清楚地说明为什么这种结构没有“回溯”。
您可以编写一个惰性的递归 distinctBy 函数
implicit class DistinctStream[T](s: Stream[T]) {
def distinctBy[V](f: T => V): Stream[T] = {
def distinctBy(remainder: Stream[T], seen:Set[V]): Stream[T] =
remainder match {
case head #:: tail =>
val value = f(head)
if (seen contains value) distinctBy(tail, seen)
else Stream.cons(head, distinctBy(tail, seen + value))
case empty => empty
}
distinctBy(s, Set())
}
}
像这样使用它
def solutions(target: Int): Stream[Path] =
(for {
pathSet <- pathSets
path <- pathSet
if path.endState contains target
} yield path) distinctBy (_.endState)
是的,现在有递归。但是已经有,因为 Stream 的 map、flatMap 和 filter 函数已经都是惰性递归函数。
关于sql - 在理解中实现 DISTINCT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24454203/