Reputation: 53806
I'm trying to convert List("a,1" , "b,2" , "c,3" , "a,2" , "b,4")
to type scala.collection.immutable.HashMap[String, java.util.List[String]]
with values :
a -> 1,2
b -> 2,4
c -> 3
So each key contains a List of its values.
Here is my code so far :
object ConvertList extends Application {
var details = new scala.collection.immutable.HashMap[String, java.util.List[String]]
val strList = List("a,1" , "b,2" , "c,3" , "a,2" , "b,4")
//Get all values
val getValue : Function1[String, String] = { a => a.split(",")(1) }
val allValues : List[String] = strList map getValue
//get unique values
val uniqueValues = allValues.toSet[String]
//Somehow map each unique value to a value in the original List....
println(uniqueValues)
println(strList.flatten)
//userDetails += "1" -> List("a","b",
}
How can this conversion be performed ?
Upvotes: 10
Views: 18046
Reputation: 61666
Starting Scala 2.13
, we can use the new groupMap method which (as its name suggests) is a one-pass equivalent of a groupBy
and a map
ping over grouped items:
// val strList = List("a,1" , "b,2" , "c,3" , "a,2" , "b,4")
strList.map(_.split(",")).groupMap(_(0))(_(1))
// Map("b" -> List(2, 4), "a" -> List(1, 2), "c" -> List(3))
This:
splits each string (producing List(Array(a, 1), Array(b, 2), ...)
)
group
s elements based on their first part (_(0)
) (group part of groupMap)
map
s grouped elements to their second part (_(1)
) (map part of groupMap)
Upvotes: 0
Reputation: 2710
There are already a good deal of takes, but what about something similar to what Marth proposes:
import scala.collection.JavaConverters._
val strList = List("a,1" , "b,2" , "c,3" , "a,2" , "b,4")
strList.map(_.split(',')).collect {
case Array(key, value) => key -> value
}.groupBy(_._1).mapValues(_.map(_._2).asJava)
This relies heavily on functional programming and ends up with a Map
of type Map[String, java.util.List[String]]
, while not just taking fixed positions in the input string, but splitting at the comma (imagine having numbers over 9, requiring more than one digit).
Also, if there are more than one value from the split, the collect
method filters them away.
Upvotes: 3
Reputation: 20285
scala> List("a,1" , "b,2" , "c,3" , "a,2" , "b,4")
res0: List[String] = List(a,1, b,2, c,3, a,2, b,4)
scala> res0.groupBy(xs => xs.split(",")(0)).mapValues(xs => xs.flatMap(xs => xs.toCharArray.filter(_.isDigit)))
res2: scala.collection.immutable.Map[String,List[Char]] = Map(b -> List(2, 4), a -> List(1, 2), c -> List(3))
Using groupBy
makes this straight forward since you want a Map
. The groupBy
splits each element of the List
by ,
and takes the first one which is the key. That gives this:
scala.collection.immutable.Map[String,List[String]] = Map(b -> List(b,2, b,4), a -> List(a,1, a,2), c -> List(c,3))
. From here it is just processing to get the digits from each List
of values.
This returns a Map[String, List[Char]]
. There is a little more to do if you want scala.collection.immutable.HashMap[String, java.util.List[String]]
returned but that's the easy part.
Upvotes: 1
Reputation: 24812
strList.map(s => (s(0).toString,s(2).toString))
.groupBy(_._1)
.mapValues(_.map(_._2))
Output :
Map[String,List[String]] = Map(b -> List(2, 4), a -> List(1, 2), c -> List(3))
Upvotes: 15
Reputation: 62835
Lists wouldn't be in the same order, but generally it is quite feasible problem:
// for a sake of pithiness
type M = Map[String,List[String]]
def empty: M = Map.empty.withDefaultValue(Nil)
@annotation.tailrec
def group(xs: List[String], m: M = empty): M = xs match {
case Nil => m
case h::tail =>
val Array(k,v) = h.split(",")
val updated = v::m(k)
combine(tail, m + (k -> updated))
}
Upvotes: 3