Reputation: 11741
I've a Sequence of Maps
Seq[Map[String,Int]]
I want to create a Seq/Set that is the Union of all keys in each of the Map.
unionallkeys = ( "a1", "a2", "a3", "b1", "b2", "b3", "c1", "c2", "c3" )
in the example below.
scala> val a = Map( ("a1", 1), ("a2", 2), ("a3", 3) )
a: scala.collection.immutable.Map[String,Int] = Map(a1 -> 1, a2 -> 2, a3 -> 3)
scala> val b = Map( ("b1", 1), ("b2", 2), ("b3", 3) )
b: scala.collection.immutable.Map[String,Int] = Map(b1 -> 1, b2 -> 2, b3 -> 3)
scala> val c = Map( ("c1", 1), ("c2", 2), ("c3", 3) )
c: scala.collection.immutable.Map[String,Int] = Map(c1 -> 1, c2 -> 2, c3 -> 3)
scala> val misc = Map( ("a1", 1), ("b2", 2), ("c3", 3) )
misc: scala.collection.immutable.Map[String,Int] = Map(a1 -> 1, b2 -> 2, c3 -> 3)
^
scala> val rows = List(a,b,c,misc)
rows: List[scala.collection.immutable.Map[String,Int]] = List(Map(a1 -> 1, a2 -> 2, a3 -> 3), Map(b1 -> 1, b2 -> 2, b3 -> 3), Map(c1 -> 1, c2 -> 2, c3 -> 3), Map(a1 -> 1, b2 -> 2, c3 -> 3))
Upvotes: 2
Views: 1590
Reputation: 15539
Travis solution is immutable which is better in term of design.
Let me just provide a solution using mutable Set:
def keysUnion[A,B](maps: Seq[Map[A,B]]): scala.collection.Set[A] = {
val allKeys = scala.collection.mutable.Set[A]()
maps.foreach( m => allKeys ++= m.keySet )
allKeys
}
// test with some random input data
import scala.util.Random
val maps = (1 to 10).map( i => (1 to i).map( k => k -> k ).toMap )
keysUnion(maps)
I don't know if the mutable.Set is efficient. And most probably the .toSet
of the immutable solution does the same. So for simple case it should be very similar, but it should be better if the flatten list of keys is (really) big.
Note:
when using mutable collection, it's better to hide it inside method that output a trait with immutable API. This is why the solution I provided is in the form of a function which output scala.collection.Set
.
Upvotes: 0
Reputation: 139038
You can write this as a fairly clear one-liner:
scala> val keys: Set[String] = rows.flatMap(_.keySet).toSet
keys: Set[String] = Set(c3, b2, b3, c2, b1, c1, a3, a1, a2)
Let's break this down step by step. First of all, the keySet
method on a map will give you a set of the map's keys. If you wanted a list of sets of keys, you could just write the following:
scala> val keySets: List[Set[String]] = rows.map(_.keySet)
keySets: List[Set[String]] = List(Set(a1, a2, a3), Set(b1, b2, b3), ...
You could then flatten the nested structure:
scala> val keyList: List[String] = keySets.flatten
keyList: List[String] = List(a1, a2, a3, b1, b2, b3, c1, c2, c3, a1, b2, c3)
Note that the result has the type of the outer collection—i.e. it's a list, not a set. You can convert it to a set with toSet
:
scala> val keys: Set[String] = keyList.toSet
keys: Set[String] = Set(c3, b2, b3, c2, b1, c1, a3, a1, a2)
And you're done. The first line above just does all of these steps at once, and combines the map
and flatten
calls into a single flatMap
.
Upvotes: 7