我是scala的新手,正在尝试编写函数,该函数返回给定字符串中每个字母的所有索引的map。我的代码:
def group(string: String) = {
val map = mutable.Map[Char, ListBuffer[Int]]()
for (i <- string.indices) {
val ch = string(i)
if(map.contains(ch)) map(ch) += i
else map += (ch -> ListBuffer(i))
}
map
}
尝试编译时出现错误:
错误:(14,30)类型参数[?,Iterable [Any] with PartialFunction [Int with Char,Any] with scala.collection.generic.Subtractable [_>:Int with Char <:AnyVal,Iterable [Any ]与PartialFunction [Int with Char,Any] with scala.collection.generic.Subtractable [_>:Int with Char <:AnyVal,Iterable [Any] with PartialFunction [Int with Char,Any] with scala.collection.generic.Subtractable [_>:带有Char的整数<:AnyVal,等于]] {def seq:具有PartialFunction [Int与Char,Any]的Iterable [Any]}] {def seq:具有PartialFunction [具有Char,Any与Int的Iterable [Any] {def seq:Iterable [Any] with PartialFunction [Int with Char,Any]}}]不符合特征Subtractable的类型参数范围[A,+ Repr <:scala.collection.generic.Subtractable [A,Repr]] val v = for(i <-string.indices){
似乎循环值有问题。所以我已经添加到循环“ true”的最后一行,现在一切正常:
def group(string: String) = {
val map = mutable.Map[Char, ListBuffer[Int]]()
for (i <- string.indices) {
val ch = string(i)
if(map.contains(ch)) map(ch) += i
else map += (ch -> ListBuffer(i))
true
}
map
}
我的代码有什么问题,我该如何解决? Scala版本:2.12.6
答案 0 :(得分:2)
未编译方法的原因是因为您返回的是与if-else
表达式完全不同的类型。一个返回ListBuffer[Int]
,另一个返回Map[Char, ListBuffer[Int]]
。
您想要的是:
def group(string: String): mutable.Map[Char, ListBuffer[Int]] = {
val map = mutable.Map[Char, ListBuffer[Int]]()
for (i <- string.indices) {
val ch = string(i)
if (map.contains(ch)) {
map(ch) += i
map
} else map += (ch -> ListBuffer(i))
}
map
}
没有可变的Map
或ListBuffer
的另一种方法可能是:
def group(s: String): Map[Char, Int] = {
s.split("\\W+")
.flatten
.zipWithIndex
.groupBy { case (char, _) => char }
.mapValues { arr => arr.map(_._2) }
}
答案 1 :(得分:2)
您在https://docs.scala-lang.org/tutorials/FAQ/yield.html中看到
Scala的“ for comprehensions”是语法糖,用于使用foreach,map,flatMap,filter或withFilter组合多个操作。 Scala实际上将for表达式转换为对这些方法的调用,因此提供它们的任何类或其中的一个子集都可以用于理解。
因此,您的for
循环
for (i <- string.indices) {
val ch = string(i)
if(map.contains(ch)) map(ch) += i
else map += (ch -> ListBuffer(i))
}
等同于
string.indices.foreach(i => {
val ch = string(i)
if(map.contains(ch)) map(ch) += i
else map += (ch -> ListBuffer(i))
})
foreach
方法界面是
def foreach[U](f: A => U): Unit
map(ch) += i
返回ListBuffer
,但是map += (ch -> ListBuffer(i))
返回Map
。并且,当编译器尝试在U
参数foreach
中标识f: Int => U
时,它会在ListBuffer
和Map
之间获得某些东西,而不会对其进行编译。
此外,如果您不在某处使用编译器,则编译器不会检查if-else表达式的结果类型。
您可以通过这样重写代码来修复代码
def group(string: String) = {
val map = mutable.Map[Char, ListBuffer[Int]]()
def update(i: Int): Unit = {
val ch = string(i)
if(map.contains(ch)) map(ch) += i
else map += (ch -> ListBuffer(i))
}
for (i <- string.indices) update(i)
map
}
但是最好使用标准方法
def group(string: String) = string.toCharArray.zipWithIndex.groupBy(_._1).mapValues(_.map(_._2))
答案 2 :(得分:1)
您不需要保留ListBuffer来保留索引,我们只需使用新的附加索引列表更新地图条目即可。
def group(string: String): mutable.Map[Char, List[Int]] = {
val map = mutable.Map.empty[Char, List[Int]]
string.zipWithIndex.foreach { case (char: Char, index: Int) =>
map += (char -> (index :: map.get(char).getOrElse(List())))
}
map
}