2014-09-04 53 views
4

我有一個數組,這樣的事情陣列GROUPBY和返回數組索引相關指標的集合,每個這樣的組,即對於一個給定的數組的答案是:Scala集合:</p> <pre><code>val a = Array("a", "c", "c", "z", "c", "b", "a") </code></pre> <p>,我希望得到一個地圖有此數組和值的所有不同值的鍵:每個組

Map(
    "a" -> Array(0, 6), 
    "b" -> Array(5), 
    "c" -> Array(1, 2, 4), 
    "z" -> Array(3) 
) 

出人意料的是,它被證明是稍微複雜一些,我已經預料到的。到目前爲止我所得到的最好的是:

a.zipWithIndex.groupBy { 
    case(cnt, idx) => cnt 
}.map { 
    case(cnt, arr) => (cnt, arr.map { 
    case(k, v) => v 
    } 
} 

這不是簡明扼要或容易理解。任何更好的想法?

回答

5

您的代碼可以重寫爲oneliner,但看起來很醜。

as.zipWithIndex.groupBy(_._1).mapValues(_.map(_._2)) 

另一種方法是使用mutable.MultiMap

import collection.mutable.{ HashMap, MultiMap, Set } 

val as = Array("a", "c", "c", "z", "c", "b", "a") 
val mm = new HashMap[String, Set[Int]] with MultiMap[String, Int] 

,然後只需添加每結合

as.zipWithIndex foreach (mm.addBinding _).tupled  
//mm = Map(z -> Set(3), b -> Set(5), a -> Set(0, 6), c -> Set(1, 2, 4)) 

終於可以將其轉換mm.toMap如果你想一成不變的版本。

+0

我不認爲第一個1是醜陋的,品味的問題。 – samthebest 2014-09-04 07:52:32

+2

也許稍微不那麼醜陋的單行'a.zipWithIndex.groupBy(_._ 1).mapValues(_。unzip._2)' – 2014-09-04 10:04:23

2

這是foldRight的版本。我認爲這很清楚。

val a = Array("a", "c", "c", "z", "c", "b", "a") 
a 
.zipWithIndex 
.foldRight(Map[String, List[Int]]()) 
      {case ((e,i), m)=> m updated (e, i::m.getOrElse(e, Nil))} 
//> res0: scala.collection.immutable.Map[String,List[Int]] = Map(a -> List(0, 6) 
//| , b -> List(5), c -> List(1, 2, 4), z -> List(3)) 
2

使用foldLeft和不可改變Map默認值的另一種版本:

val a = Array("a", "c", "c", "z", "c", "b", "a") 
a.zipWithIndex.foldLeft(Map[String, List[Int]]().withDefaultValue(Nil))((m, p) => m + ((p._1, p._2 +: m(p._1)))) 

// res6: scala.collection.immutable.Map[String,List[Int]] = Map(a -> List(6, 0), c -> List(4, 2, 1), z -> List(3), b -> List(5)) 
相關問題