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