2011-10-01 6 views
16

私はスカラーを初めて使い、おそらくかなり簡単な質問があります。 List((Int、String))という形式の2つのリストがあり、文字列が同じであるIntegersを結合したい。たとえば:文字列が同じであれば、私はリストの両方を横断して追加している今スカラーで2つのリストを結合する

l3 = List((4,"a"),(3,"b"),(4,"c")) 

を、私:

l1 = List((1,"a"),(3,"b")) 
l2 = List((3,"a"),(4,"c")) 

私はそうのように3番目のリストにこれらを結合したいですパターンマッチングのある単純な解決策があるはずだと考えています。どんな助けもありがとうございます。

+1

同様の質問:http://stackoverflow.com/questions/7076128/best-way- to-merge-two-maps-and-sum-of-same-key – Infinity

+0

ListだけでなくList [(String、Int)]を使用すると、 (Int、String)]? –

答えて

20
val l = l1 ::: l2 
val m = Map[String, Int]() 
(m /: l) { 
    case (map, (i, s)) => { map.updated(s, i + (map.get(s) getOrElse 0))} 
}.toList // Note: Tuples are reversed. 

しかし、updatedの部分を行うよりエレガントな方法があると思います。

+0

ありがとうございます。それはまさに私が探しているものです。もしできれば、私はあなたに投票します。 –

0

この解決策では、リストは2回トラバースされることに注意してください。少しREPLでこれを開梱

val l3 = (l1 zip l2).foldRight(List[(Int, String)]()) { 
    case ((firstPair @ (firstNumber, firstWord), 
     secondPair @ (secondNumber, secondWord)), 
     result) => 
    if (firstWord == secondWord) 
     ((firstNumber + secondNumber), firstWord) :: result 
    else 
     firstPair :: secondPair :: result 
} 
19

方法について、

(l1 ++ l2).groupBy(_._2).mapValues(_.unzip._1.sum).toList.map(_.swap) 

が、これは簡単です、何が起こっているかを示すために役立ちますScalaz

scala> l1 ++ l2 
res0: List[(Int, java.lang.String)] = List((1,a), (3,b), (3,a), (4,c)) 

scala> res0.groupBy(_._2) 
res1: ... = Map(c -> List((4,c)), a -> List((1,a), (3,a)), b -> List((3,b))) 

scala> res1.mapValues(_.unzip) 
res2: ... = Map(c -> (List(4),List(c)), a -> (List(1, 3),List(a, a)), b -> (List(3),List(b)))       

scala> res1.mapValues(_.unzip._1)                                          
res3: ... = Map(c -> List(4), a -> List(1, 3), b -> List(3))                      

scala> res1.mapValues(_.unzip._1.sum) 
res4: ... = Map(c -> 4, a -> 4, b -> 3)                            

scala> res4.toList                                              
res5: List[(java.lang.String, Int)] = List((c,4), (a,4), (b,3))                                   

scala> res5.map(_.swap) 
res6: List[(Int, java.lang.String)] = List((4,c), (4,a), (3,b)) 
+2

改行なしで関数を実装できるたびに、私は自分自身に背を向けている傾向がありますが、それはかなり不透明です!それが正しいことを明白にする中間体にいくつかの名前を付けることができますか? –

+0

(l1 ++ l2)から(l1 ++ l2).groupBy(_._2)...などで始まるREPLの最初から最後までの各中間結果を処理することをお勧めします。 –

+0

私は興味を持っていましたが、実際にソースベースでそのようなコードを残すか、変数名を説明して分割しますか? –

10

import scalaz._ 
import Scalaz._ 

val l3 = (l1.map(_.swap).toMap |+| l2.map(_.swap).toMap) toList 

|+|方法は、Semigroup[T]の実装が存在Tするすべてのタイプに露出しています。 Map[String, Int]のセミグループは、まさにあなたが望むものです。

0

別の不透明まだ疑問効率の1 2-ライナーは間違いのない有効性:

val lst = l1 ++ l2 
lst.map(_._2).distinct.map(i => (lst.filter(_._2 == i).map(_._1).sum, i)) 
1
for ((k,v) <- (l1++l2).groupBy(_._2).toList) yield (v.map(_._1).sum, k) 
0
val a = List(1,1,1,0,0,2) 
val b = List(1,0,3,2) 

scala> List.concat(a,b) 
res31: List[Int] = List(1, 1, 1, 0, 0, 2, 1, 0, 3, 2) 

(or) 

scala> a.:::(b) 
res32: List[Int] = List(1, 0, 3, 2, 1, 1, 1, 0, 0, 2) 

(or) 

scala> a ::: b 
res28: List[Int] = List(1, 1, 1, 0, 0, 2, 1, 0, 3, 2) 
関連する問題