简体   繁体   中英

Iterable[Try[(K, V)]] to Try[Map[K, V]]

I have a method load which is relatively expensive to call. In order to allow some kind of exception handling during loading it returns a Try . I need now an implementation for the loadAll method which basically delegates to load for each of the given keys. Here is my first approach, however I don't know if this is best practices with respect to the work with Try . Is there a better way to achieve the following?

def load(key: K): Try[V] // very expensive

def loadAll(keys: Traversable[K]): Try[Map[K, V]] = {

  // remove duplicate keys
  val ukeys = Set.empty ++ keys

  val result: Iterable[Try[(K, V)]] = ukeys map { key =>
    load(key) match {
      case Success(value)     => Success(key, value)
      case Failure(exception) => Failure(exception)
    }
  }

  Try(result.map { _.get }.toMap)
}

You can do this using a fold to iterate over the keys, and a for comprehension to combine the Try instances:

def toSet(keys: Traversable[K]): Try[Map[K, V]] = {
  keys.toSet.foldLeft( Try( Map.empty[K, V] ) ){ case (tryMap, key) => 
    for ( m <- tryMap; v <- load( key ) ) yield m.updated( key, v )
  }
}

If you're interested in a scalaz solution, this is a general operation, available via Traversable functors, called sequence . Needed instances for Try reside in scalaz-contrib . Here's how it might look like:

Welcome to Scala version 2.10.1 (OpenJDK 64-Bit Server VM, Java 1.7.0_21).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import scalaz._, Scalaz._, scalaz.contrib.std.utilTry._
import scalaz._
import Scalaz._
import scalaz.contrib.std.utilTry._

scala> import scala.util.Try
import scala.util.Try

scala> val result: Iterable[Try[(Int, String)]] = Iterable.empty
result: Iterable[scala.util.Try[(Int, String)]] = List()

scala> result.toList.sequence.map(_.toMap)
res0: scala.util.Try[scala.collection.immutable.Map[Int,String]] = Success(Map())

By the way, there's a paper "The essence of the Iterator pattern" , describing/deriving traverse (and sequence , as it's special case). There's a great summary of this paper by Eric Torreborre here.

这是一个香草Scala的单行(假设你已经Try了范围):

def loadAll(keys: Traversable[K]) = Try{ keys.toSet.map((k: K) => (k,load(k).get)).toMap }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM