2013-08-29 265 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方法將它們過濾掉。