问题
I have a collection of objects
case class Record(value: Whatever)
val list: List[Record]
and want to select the best ranked
list.foldLeft(list.head) { (best, current) =>
if (rank(current.value) > rank(best.value)) {
current
} else {
best
}
}
Let's suppose that rank
is expensive and better not be called twice on the same object. What are my options?
I can fold to tuple (rank, record)
but this probably means creating auxiliary objects during iteration. Should I worry about the overhead? Or rather
How can this be implemented efficiently in Scala?
What's the proper 'functional' view of the problem?
回答1:
If you're in a situation where repeating expensive calculations on the same objects appears unavoidable, you might try memoization.
// memoize this function (arity 1)
def memo[A,R](f :A => R): A => R =
new collection.mutable.WeakHashMap[A,R] {
override def apply(a: A) = getOrElseUpdate(a,f(a))
}
// rankM is a memoized Record => Rank function
val rankM = memo{ r:Record => rank(r.value) }
A WeakHashMap
is used sometimes when you want the Map
to "forget" seldom accessed keys in a memory-challenged environment.
回答2:
The initial value in foldLeft can be of a different type than collection, so you could initialize it with tuple, that would contain current element and calculated value:
val (result, _) = list.foldLeft((list.head, rank(list.head))) { case ((best, bestRank), current) =>
val currentRank = rank(current.value)
if (rank(current.value) > bestRank) {
(current, currentRank)
} else {
(best, bestRank)
}
}
But as was mentioned in comments maybe in your case, it would be better to just use: list.maxBy(r => rank(r.value))
?
来源:https://stackoverflow.com/questions/61674271/intermediate-values-during-folding