Intermediate values during folding?

為{幸葍}努か 提交于 2020-06-28 03:59:12

问题


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

  1. How can this be implemented efficiently in Scala?

  2. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!