Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala和映射值_Scala_Map_Casting - Fatal编程技术网

Scala和映射值

Scala和映射值,scala,map,casting,Scala,Map,Casting,我有一张单子 val l : List[Map[String,Any]] = List(Map("a" -> 1, "b" -> 2.8), Map("a" -> 3, "c" -> 4), Map("c" -> 5, "d" -> "abc")) 我使用下面的代码来计算键“a”(Int)、“b”(Double)和“c”(Int)的和。“d”包括在噪声中 l.map(n => n.mapValues( v => if (v.isI

我有一张单子

    val l : List[Map[String,Any]] = List(Map("a" -> 1, "b" -> 2.8), Map("a" -> 3, "c" -> 4), Map("c" -> 5, "d" -> "abc"))
我使用下面的代码来计算键“a”(Int)、“b”(Double)和“c”(Int)的和。“d”包括在噪声中

    l.map(n => n.mapValues( v => if (v.isInstanceOf[Number]) {v match {
    case x:Int => x.asInstanceOf[Int]
    case x:Double => x.asInstanceOf[Double]
    }} else 0)).foldLeft((0,0.0,0))((t, m) => (
t._1 +  m.get("a").getOrElse(0), 
t._2 + m.get("b").getOrElse(0.0), 
t._3 + m.get("c").getOrElse(0)))
我希望输出是(4,2.8,9),但是我被它给毁了

<console>:10: error: overloaded method value + with alternatives:
  (x: Int)Int <and>
  (x: Char)Int <and>
  (x: Short)Int <and>
  (x: Byte)Int
 cannot be applied to (AnyVal)
:10:错误:重载的方法值+带有可选项:
(x:Int)Int
(x:Char)Int
(x:Short)Int
(x:Byte)Int
无法应用于(AnyVal)

我认为异常是试图告诉我“+”不适用于AnyVal。我如何让它工作,以得到我想要的结果?谢谢

您可以使用foldLeft功能:

scala> val l : List[Map[String,Any]] = List(Map("a" -> 1, "b" -> 2.8), Map("a" -> 3, "c" -> 4), Map("c" -> 5, "d" -> "abc"))
l: List[Map[String,Any]] = List(Map(a -> 1, b -> 2.8), Map(a -> 3, c -> 4), Map(c -> 5, d -> abc))

scala> val (sa, sb, sc) = l.foldLeft((0: Int, 0: Double, 0: Int)){
     |   case ((a, b, c), m) => (
     |     a + m.get("a").collect{case i: Int => i}.getOrElse(0),
     |     b + m.get("b").collect{case i: Double => i}.getOrElse(0.),
     |     c + m.get("c").collect{case i: Int => i}.getOrElse(0)
     |     )
     |   }
sa: Int = 4
sb: Double = 2.8
sc: Int = 9

通常,如果您不知道键,但只想求和您可以做的值,则使用incrop的
collect
思想更新,而不是
match

val filtered = for {
    map <- l
    (k, v) <- map
    if v.isInstanceOf[Number]
  } yield k -> v.asInstanceOf[Number].doubleValue

val summed = filtered.groupBy(_._1) map { case (k, v) => k -> v.map(_._2).sum }

scala> l
res1: List[Map[String,Any]] = List(Map(a -> 1, b -> 2.8), Map(a -> 3, c -> 4), Map(c -> 5, d -> abc))

scala> filtered
res2: List[(String, Double)] = List((a,1.0), (b,2.8), (a,3.0), (c,4.0), (c,5.0))

scala> summed
res3: Map[String,Double] = Map(c -> 9.0, a -> 4.0, b -> 2.8)

首先,你完全没有抓住模式匹配的重点

{case i: Int => i
 case d: Double => d
 case _ => 0} 
是否正确替换了
mapValues
中的所有函数。但这不是问题所在,你的写作虽然复杂,但也有同样的作用

mapValues
中的函数返回
Double
(因为一些分支返回
Int
,而其他分支返回
Double
,在这种情况下,
Int
被提升为
Double
。如果不是,它将返回
AnyVal
)。 因此,您将得到一个
列表[Map[String,Double]]
。此时,您已丢失Ints

当您执行
m.get(“a”)
时,将返回
选项[Double]
<代码>选项[A]有方法getOrElse(默认值:A):A(实际上,
默认值:=>X
),但在这里没有区别)

如果您调用
getOrElse(0.0)
而不是
getOrElse(0)
,则会得到一个双精度。代码仍然失败,因为折叠以(Int,Double,Double)开始,然后返回(Double,Double,Double)。如果你以(0.0,0.0,0.0)开始折叠,它会工作,但是你失去了整数,你会得到(4.0,2.8,9.0)

现在,关于错误消息。如果将Int传递给一个需要Double(getOrElse)的方法,Int通常应转换为Double,这就好像使用
getOrElse(0.0)
调用一样。除了
选项
是协变的(声明的
特征选项[+A]
)。如果
X
A
的祖先,那么
选项[A]
也是
选项[X]
。因此,O
Option[Double]
也是
选项[AnyVal]
选项[Any]
。如果将该选项视为一个
选项[AnyVal]
,则调用
getOrElse(0)
有效,结果是
AnyVal
(也可以与
Any
一起使用,但
AnyVal
更精确,这是编译器选择的选项)。由于表达式按原样编译,因此无需将
0
升级为
0.0
。因此,
m.get(“a”).getOrElse(0)
属于
AnyVal
类型,不能添加到
t.\u 1
。这就是您的错误消息所说的

您知道“a”与Int相关联,“b”与double相关联,但您没有将此知识传递给编译器

漂亮的单衬里:

l.map(_.filterKeys(_ != "d")).flatten groupBy(_._1) map { case (k,v) => v map { case (k2,v2: Number) => v2.doubleValue} sum }

res0: scala.collection.immutable.Iterable[Double] = List(9.0, 4.0, 2.8)

我是否遗漏了什么,或者你是否能做到:

map.values.sum
?

这是一个非常清晰和简单的解决方案。
引用:

@paragmatic:Not“精确”:使用
选项[Any].getOrElse
您将获得
Any
,使用
match/case
您将获得所需的类型。@paragmatic:代替
m.get(“a”).getOrElse(0)
您可以使用
m.getOrElse(“a”,0)
,但是您仍然会得到
Any
。您可以使用
collect
来获得所需的类型:
m.get(“a”).collect{case x:Int=>x}.getOrElse(0)
,虽然它很简洁,但使用这个解决方案,我就剩下了所有的双精度。有没有办法保留类型?在这种情况下,我只能考虑按某种类型筛选映射。是的,您缺少了一些内容。需要每个键的总和,并且这些值具有不同的类型
l.map(_.filterKeys(_ != "d")).flatten groupBy(_._1) map { case (k,v) => v map { case (k2,v2: Number) => v2.doubleValue} sum }

res0: scala.collection.immutable.Iterable[Double] = List(9.0, 4.0, 2.8)
map.values.sum
m.foldLeft(0)(_+_._2)