在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
endState
pathSets
Map
的方法。
有没有办法从相同理解的过滤条款中回溯到已经产生的项目?
另一种方法可能是在endState
语句之前将path
从for
转换为Stream
到Stream
,然后将其转换回{{ 1}}在返回之前。但是,这似乎会失去使用Set
的懒惰计算优势。
同一个案例研究的早期方法完成了类似的目标,但它已经是一个递归函数,而这个函数似乎不需要递归。
看起来我可以使用可变endState
来跟踪得到的{{1}},但这感觉不满意,因为到目前为止该课程已成功避免使用可变性。
答案 0 :(得分:1)
有没有办法从相同理解的过滤条款中回溯到已经产生的项目?
你理解的东西或多或少像是
pathSets flatMap {
pathSet => pathSet filter {
path => path.endState contains target
}
} map {path => path}
具有身份功能的最后一张地图是你的收益。我不记得规范是否允许该地图在身份识别功能时被省略。
无论如何,我希望这更清楚地说明为什么没有“回到”那个结构。
你可以写一个懒惰的,递归的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函数都已经是懒惰的递归函数了。