[英]Why does this scala fold return Equals types?
我正试图在斯卡拉返回地图。 这是我的代码:
val interestRegEx = """(\w+) Interests \((.+ Interest)\)""".r
val singleAttributes = Seq("Sport Interests (Some Interest):Running,Swimming","Something else:True")
val interests = singleAttributes.map { x =>
// e.g. ("Sport Interests (Some Interest)", "Running,Swimming") should
// result in ("Sport Running" -> "Some Interest", "Sport Swimming" -> "Some Interest")
val attVal = x.split(':')
attVal(0) match {
case interestRegEx(interestProduct, interestAmount) =>
Some(attVal(1).split(",").map { i =>
Map(s"$interestProduct $i" -> interestAmount)
}.reduce(_ ++ _))
case _ => None
}
}.fold(Map[String, String]())(_) //.reduce(_ + _)
问题是试图将集合简化为单个Map [String,String]。 我以为折叠可能有用,但由于它也许根本不需要,所以以后甚至不需要添加reduce(_ + _)
,但这也不起作用。
我不了解的部分是IntelliJ告诉我interests
类型为((Equals, Equals) => Equals) => Equals
。 WTF? 这些Equals
来自何处,为什么不将所有Maps加在一起以返回包含所有键和值的Map?
如果我们简化您的示例,我们将得到:
val interests = Seq[String]().map { x =>
Option[Map[String, String]](Map("k" -> "v"))
}.fold(Map[String, String]())(_)
这意味着我们正在尝试将Seq[Option[Map[String, String]]]
fold
为初始值Map[String, String]()
:
def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op)
从fold
定义中,我们可以看到编译器期望Option[Map[String, String]]
(折叠中的每个值)和Map[String, String]
(初始值)应为同一类型。
如果检查Option
层次结构,将看到:
Option
-> Product
-> Equals
对于Map
我们具有以下内容:
Map
- > GenMap
- > GenMapLike
- > Equals
(性状层次复杂,可能是另一个链存在)。
因此,我们可以看到最接近的常见类型是Equals
。
难题的第二部分是(_)
。
编译器将其视为lambda的参数:
val interests = x => /*omited*/.fold(Map[String, String]())(x)
我们看到x
是(A1, A1) => A1
。 在我们的例子中是:
(Equals, Equals) => Equals
fold
Equals
的结果是A1
,它也Equals
。
因此,lambda类型为:
((Equals, Equals) => Equals) /*<< arg*/ => /*result >>*/ Equals
更新:
为了解决您的问题,我认为您应该使用:
.flatten.reduce(_ ++ _)
当您获得诸如Product
或Equals
的特征作为语句的推断类型时,通常可以打赌您在某些高阶函数中类型不匹配。 通常不会得到Any
或AnyRef
因为只有在某些类型的集合没有共同之处时才会发生。 我想知道的一件事是,您的fold
的第二个参数仅采用一个参数。 足够令人惊讶的是,它进行了类型检查,但这可能是为您提供了您所不期望的类型的原因。
我认为您想做的更像是:
val interestRegEx = """(\w+) Interests \((.+ Interest)\)""".r
val singleAttributes = Seq("Sport Interests (Some Interest):Running,Swimming","Something else:True")
val interests = singleAttributes.map { x =>
// e.g. ("Sport Interests (Some Interest)", "Running,Swimming") should
// result in ("Sport Running" -> "Some Interest", "Sport Swimming" -> "Some Interest")
val attVal = x.split(':')
attVal(0) match {
case interestRegEx(interestProduct, interestAmount) =>
attVal(1).split(",").map { i =>
Map(s"$interestProduct $i" -> interestAmount)
}.reduce(_ ++ _)
case _ => Map.empty
}
}.reduce(_ ++ _)
为此,我得到了:
scala> interests
res0: scala.collection.immutable.Map[_ <: String, String] = Map(Sport Running -> Some Interest, Sport Swimming -> Some Interest)
我摆脱了在您的正则表达式匹配中包装Map
的Option
。 由于您打算合并地图,因此最好将空白地图用作不匹配的情况。 然后,就像您在内部map
所做的一样,我使用reduce
而不是fold
来进行最终比赛。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.