我对Scala编程完全不熟悉,我遇到了以下问题:
我需要一个HashMap,它可以包含许多数据类型(Int,String等)。在C ++中,我会使用BOOST的MultiMap。我听说在Scala中有一个MultiMap特征可用。基本上我想要的是以下内容:
val map = HashMap[String, ListBuffer[_]]
ListBuffer元素的具体数据类型将在运行时确定。当我在控制台中测试此实现时,以下工作:
scala> val a = new HashMap[String, ListBuffer[_]]()
a: scala.collection.mutable.HashMap[String,scala.collection.mutable.ListBuffer[_]] = Map()
scala> val b = new ListBuffer[String]()
b: scala.collection.mutable.ListBuffer[String] = ListBuffer()
scala> val c = new ListBuffer[Int]()
c: scala.collection.mutable.ListBuffer[Int] = ListBuffer()
scala> b += "String"
res0: b.type = ListBuffer(String)
scala> c += 1
res1: c.type = ListBuffer(1)
scala> a += "String Buffer" -> b
res2: a.type = Map((String Buffer,ListBuffer(String)))
scala> a += "This is an Int Buffer" -> c
res3: a.type = Map((String Buffer,ListBuffer(String)), (This is an Int Buffer,ListBuffer(1)))
所以基本上它可行。我的第一个问题是,是否有可能在Scala中实现相同的行为而不使用ListBuffer作为间接层。
获取包含以下内容的Map:Map((String,1),(String,“String value”),...)
当我现在尝试使用上面的ListBuffer-Implementation时,我收到以下类型不匹配错误:
found : _$1 where type _$1
required: _$3 where type _$3
我基本上是在尝试做以下事情:
我使用迭代器迭代地图的键:
var valueIds = new ListBuffer[Int]()
val iterator = map.keys
iterator.foreach(key => { valueIds += setValue((map.apply(key)).last) }
setValue返回Int,是一个必须对ListBuffers最后一个元素执行某些操作的方法。
有人知道如何解决上述类型不匹配问题吗?
感谢您的帮助!
此致
答案 0 :(得分:6)
您是否需要为每个密钥存储多个值?如果是这样,无论如何都需要使用ListBuffer
或其他集合。 (Scala的MultiMap
商店集,所以如果您需要保留重复项,它们将无效。)
如果您不需要为每个键存储多个值,那么您只需要Any
类型:
scala> val map = collection.mutable.HashMap[String,Any]()
map: scala.collection.mutable.HashMap[String,Any] = Map()
scala> map += "One" -> 1
res1: map.type = Map((One,1))
scala> map += "Two" -> "ii"
res2: map.type = Map((Two,ii), (One,1))
scala> map += "Three" -> None
res3: map.type = Map((Three,None), (Two,ii), (One,1))
你现在可能需要进行模式匹配或使用collect来做对值有用的任何事情:
scala> map.values.foreach(_ match { case i: Int => println("We stored the number "+i) })
We stored the number 1
scala> map.values.collect{ case i: Int => i }
res4: Iterable[Int] = List(1)
答案 1 :(得分:4)
Scala有一个MultiMap类
scala> import scala.collection.mutable.{HashMap, MultiMap, Set}
import scala.collection.mutable.{HashMap, MultiMap, Set}
scala> val a = new HashMap[String, Set[Any]] with MultiMap[String, Any]
a: scala.collection.mutable.HashMap[String,scala.collection.mutable.Set[Any]] with scala.collection.mutable.MultiMap[String,Any] = Map()
scala> a.addBinding("Pants", 1)
res0: a.type = Map((Pants,Set(1)))
scala> a.addBinding("Pants", 2)
res1: a.type = Map((Pants,Set(1, 2)))
scala> a.addBinding("Trousers", 3)
res2: a.type = Map((Trousers,Set(3)), (Pants,Set(1, 2)))
scala> a.mapValues { v => v.last }
res3: scala.collection.Map[String,Any] = Map((Trousers,3), (Pants,2))
scala> val valueIds = a.values.flatten
valueIds: Iterable[Any] = List(3, 1, 2)
我认为在查看代码时,这是有道理的。
答案 2 :(得分:1)
如果您使用占位符_
作为类型参数,则会将其转换为存在类型,即您的定义ListBuffer[_]
变为ListBuffer[A] forSome { type A }
。这意味着编译器对该类型A
一无所知,也无法对其进行任何假设。
最简单的解决方法是简单地使用ListBuffer[Any]
并使用以下内容包装地图:
val m = new HashMap[String,ListBuffer[Any]]
def get(key: String) =
m.getOrElseUpdate(key, new ListBuffer())
get("Strings") += "a"
get("Strings") += "b" += "c"
get("Ints") += 1 += 2
// m is now:
// Map(Ints -> ListBuffer(1, 2), Strings -> ListBuffer(a, b, c))
答案 3 :(得分:0)
让我再说一遍:
import scala.collection.mutable
val map = mutable.Map.empty[String, Vector[Any]].withDefaultValue(Vector.empty)
map("strings") :+= "one"
map("ints") :+= 1
map("ints") ++= Seq(1, 2)
assert {
map("default") == Vector.empty && // no side effects here
!map.contains("default")
}