2013-08-29 218 views
4

我试图转换List("a,1" , "b,2" , "c,3" , "a,2" , "b,4")与价值观键入scala.collection.immutable.HashMap[String, java.util.List[String]]字符串转换列表分为地图[字符串,列表]

a -> 1,2 
b -> 2,4 
c -> 3 

所以每个键包含其值的列表。

这里是我到目前为止的代码:

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", 


} 

怎么能这种转换进行?

+0

你对*不可变* hashmap是严格的吗? –

+0

@ om-nom-nom不,我只是想避免一个必要的解决方案。 –

回答

10
strList.map(s => (s(0).toString,s(2).toString)) 
     .groupBy(_._1) 
     .mapValues(_.map(_._2)) 

输出:

Map[String,List[String]] = Map(b -> List(2, 4), a -> List(1, 2), c -> List(3)) 
+0

你能解释's(0).toString,s(2).toString)'吗?它是否将每个字符串元素映射到一个String,String元组? –

+0

很好的答案。索引字符串确实使这个解决方案变得干净。有一个upvote。 – Brian

+1

是的,它将每个字符串映射到这对情侣('第一个字母','第三个字母')。 (所以“a,1”到(“a”,“1”))。你可以(并且应该这个代码不只是一个脑筋急转弯)编写一个函数formatString(s)并使用strList.map(formatString).groupBy(...)来更好地处理特殊情况(string.length <3,等等) – Marth

3

列表不会以相同的顺序,但通常是相当可行的问题:

// 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)) 
} 
1
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)) 

使用groupBy因为你想Map使这一直截了当。 groupByList的每个元素除以,,并采用第一个关键字。这给出了这个: scala.collection.immutable.Map[String,List[String]] = Map(b -> List(b,2, b,4), a -> List(a,1, a,2), c -> List(c,3))。从这里开始,只需处理从每个值的各个List即可获得数字。

这将返回一个Map[String, List[Char]]。如果您想返回scala.collection.immutable.HashMap[String, java.util.List[String]],还有一点要做,但这很容易。

2

已经有一个很好的协议的需要,而是类似于马斯提出的东西是什么:

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) 

这在很大程度上依赖于函数式编程和结束与Map[String, java.util.List[String]]类型的Map相关,而不仅仅是在输入字符串中占据固定位置,而是以逗号分隔(想象数字已超过9,需要多个数字)。

另外,如果拆分中有多个值,则collect方法将它们过滤掉。