collections - Scala: build a Map from a List of tuples, but fail if there are contradictory entries -
i think might common operation. maybe it's inside api can't find it. i'm interested in efficient functional/simple solution if not.
given sequence of tuples ("a" -> 1, "b" ->2, "c" -> 3) want turn map. that's easy using traversableonce.tomap. want fail construction if resulting map "would contain contradiction", i.e. different values assigned same key. in sequence ("a" -> 1, "a" -> 2). duplicates shall allowed.
currently have (very imperative) code:
def buildmap[a,b](in: traversableonce[(a,b)]): option[map[a,b]] = {   val map = new hashmap[a,b]   val = in.toiterator   var fail = false   while(it.hasnext){     val next = it.next()     val old = map.put(next._1, next._2)     fail = old.isdefined && old.get != next._2   }    if(fail) none else some(map.tomap) } side question
is final tomap necessary? type error when omitting it, think should work. implementation of tomap constructs new map want avoid.
as when working seq[a] optimal solution performance-wise depends on concrete collection type. general not efficient solution fold on option[map[a,b]]:
def optmap[a,b](in: iterable[(a,b)]): option[map[a,b]] =    in.iterator.foldleft(option(map[a,b]())) {     case (some(m),e @ (k,v)) if m.getorelse(k, v) == v => some(m + e)     case _ => none   } if restrict using list[a,b]s optimized version be:
@tailrec def rmap[a,b](in: list[(a,b)], out: map[a,b] = map[a,b]()): option[map[a,b]] = in match {   case (e @ (k,v)) :: tail if out.getorelse(k,v) == v =>     rmap(tail, out + e)   case nil =>     some(out)   case _ => none } additionally less idiomatic version using mutable maps implemented this:
def mmap[a,b](in: iterable[(a,b)]): option[map[a,b]] = {   val dest = collection.mutable.map[a,b]()    (e @ (k,v) <- in) {     if (dest.getorelse(k, v) != v) return none     dest += e   }    some(dest.tomap) } 
Comments
Post a Comment