适当的Scala Collection类似于Python Dictionary

时间:2016-05-13 08:19:06

标签: scala

我有一个迭代返回(key, value)的算法。我想要做的是将这些结果存储在一个结构中,如果key不存在,它将添加它和相应的value。现在,如果密钥存在,它会将value附加到现有的值数组。

在python中,我可以使用这种格式的python字典来完成这个:

dict = {'key1': [val1, val2, val3],
        'key2': [val4, val5], 
        'key3': [val6], ... }

简单地做:

if key in dict.keys():
    dict[key].append(value)
else:
    dict[key] = [value]

我如何在Scala中执行此操作?

2 个答案:

答案 0 :(得分:1)

也许是这样的?

scala> def insert[K,V](k: K, v: V, m: Map[K, List[V]]): Map[K, List[V]] = {
     | if (m contains k) m + (k -> (m(k) :+ v))
     | else m + (k -> List(v)) }
insert: [K, V](k: K, v: V, m: Map[K,List[V]])Map[K,List[V]]

scala> insert('b', 23, Map('b' -> List(2)))
res30: Map[Char,List[Int]] = Map(b -> List(2, 23))

scala> insert('b', 23, Map('c' -> List(2)))
res31: Map[Char,List[Int]] = Map(c -> List(2), b -> List(23))

或者,结合谢尔盖的非常好的建议:

def insert[K,V](k: K, v: V, m: Map[K, List[V]]): Map[K, List[V]] =
  m + (k -> (m.getOrElse(k, List()) :+ v))

答案 1 :(得分:0)

由于Scala中强大的类型系统,您可以以更一般的方式执行此操作:

import scalaz._, Scalaz._

case class CollectingMap[K, V, C[_]](underlying: Map[K, C[V]] = Map[K, C[V]]()) {
  def add(key: K, value: V)(implicit s: Monoid[C[V]], a: Applicative[C]): CollectingMap[K, V, C] = {
    // Either get the old value from the underyling map or the empty collection, provided by the Monoid[C[V]]
    val oldValue = underlying.get(key).getOrElse(mzero[C[V]])
    // Append the old vlaue to the new value, provided by Monoid |+|.
    // value.point[C] is provided by the Applicative, which allows us to lift the value into the collection C.
    val newValue = oldValue |+| value.point[C]
    // return the updated value, wrapped into CollectingMap again.
    CollectingMap(underlying.updated(key, newValue))
  }
}

示例:

val m = CollectingMap[Int, String, List]()
m.add(2, "bar").add(2, "foo")
// => res4: CollectingMap[Int,String,List] = CollectingMap(Map(2 -> List(bar, foo)))