【问题标题】:Scala error iterating through list of maps in for loopScala错误遍历for循环中的映射列表
【发布时间】:2015-11-27 05:27:05
【问题描述】:

我目前正在学习 scala,但对遇到的错误感到困惑。我正在尝试使用不同的容器,目前我有一个地图列表,每个地图共享相同的键。我正在尝试使用 for 循环遍历列表并将与键“startlocation”相对应的值放入 Node 类型的数组(我创建的类),但我似乎无法获得正确的语法。它告诉我我的键是一个不正确的参数,同时试图从我在列表中的当前映射中获取该键的值。

这段代码有什么问题,我应该怎么做才能修复它?

class Node{
     var visited = false;
     var mDistance = 10000;
     var prevLoc = " ";
}

object test{
  def main(args: Array[String]){

    var i = 0;
    var l = List(Map("startlocation" -> "Kruthika's abode", "endlocation" -> "Mark's crib", "distance" -> 10), 
                Map("startlocation" -> "Mark's Crib", "endlocation" -> "Kirk's Farm", "distance" -> 9));
   var b = new Array[Node](l.size);       
   var index = 0;
   for(i <- l){

       b(index).prevLoc = i("startlocation");    // This is the line where the error occurs
       index++;
    }


 }
}

具体错误:类型不匹配;找到:任何必需的:字符串

此错误突出显示我上面评论的行中的“startlocation”。

【问题讨论】:

  • 注意:for 推导式会创建自己的局部变量,因此 for (i &lt;- l) 会创建 i 类型的 Map[String,Any]。你是var i = 0 创建了一个从未使用过的Int 类型的变量。

标签: scala


【解决方案1】:

错误

异构地图

首先,您的地图定义存在很大问题。由于您使用IntString 作为值类型,因此结果类型被推断为这些值的最可能的具体公共超类型,即Any,因为StringInt 完全不同。

正确的方法?看起来您的地图旨在具有预定义的一组键,在 scala 中通过classes 甚至更好的case classes 更好地实现,因此您可以在Node 类附近定义

case class Route(startLocation: String, endLocation: String, distance: Int)

以后

val l = List(
  Route( startLocation = "Kruthika's abode",  endLocation = "Mark's crib", distance = 10),
  Route( startLocation = "Mark's Crib", endLocation = "Kirk's Farm", distance = 9))

甚至

val l = List(
      Route( "Kruthika's abode", "Mark's crib",  10),
      Route( "Mark's Crib", "Kirk's Farm",  9))

最后

b(index).prevLoc = i.startLocation    // This is the line where the error occurs

++

scala 中没有后缀++ 运算符,所以你的index++ 至少应该是index += 1

风格指南

variables

很多时候你可以避免var定义。

例如var i = 0; 是多余的,因为它甚至没有在您的代码中使用 因为在for(i &lt;- l) 中创建了新的i 定义,该定义仅在循环内有效

你也可以避免定义var index,你可以用索引遍历集合

for((i, index) <- l.zipWithIndex)

不变性

同样,您可以经常在 classes 中避免使用 variables,从而使类不可变。您可以在每次需要时创建新实例(可能是.copy()ing exisitng),而不是进行变异。

这对你的代码至关重要,因为b(index).prevLoc 肯定会抛出NullPointerException,因为在你的数组中没有创建Node 的实例。

想象一下你定义的

case class Node(visited: Boolean = false,  mDistance: Int  = 10000, prevLoc: String = " ")

而使用是as

Node(prevLoc = i.startLocation)

for (list ≺ sequence ≺ monad) 推导

最后,您的b 现在可以转换为不可变Listval,因为for 是通过yield 从现有集合创建新集合的表达式。有了这样的声明,你甚至不需要知道当前索引,所以你可以放弃建议的 .zipWithIndex 部分

;

最后,您几乎可以随时避免在行尾出现;

总结,整个代码可以翻译成

case class Node(visited: Boolean = false,  mDistance: Int  = 10000, prevLoc: String = " ")

case class Route(startLocation: String, endLocation: String, distance: Int)


object test{
  def main(args: Array[String]){

    val l = List(
      Route( "Kruthika's abode", "Mark's crib",  10),
      Route( "Mark's Crib", "Kirk's Farm",  9))

    val b = for(i <- l) yield Node(prevLoc = i.startLocation)
  }
}

您可以将println(b) 添加到main 方法的末尾以查看如何打印Listcase classes

【讨论】:

  • 干得好,但是zipWithIndex 创建了一个您不需要或不需要的索引。
  • @jwvh 不错的收获。固定
【解决方案2】:

这是因为您的地图中混合了 String 和 Int 类型。 'prevLoc' 似乎是一个字符串,但您的地图包含 Any(scala 编译器推断此类型,因为您没有指定任何类型)。

我建议您像 Map[String, String] 一样明确地显示您的地图。在这种情况下,您的程序将无法编译(您有一些整数作为映射值,所以您可以执行"distance" -&gt; 10.toString 之类的操作)。

附:尽量避免使用var:可以在没有它的情况下编写Scala代码,使用不可变变量(vals)和函数如mapfilterflatMap以函数方式。

【讨论】:

  • 我想知道是否有办法让我拥有我的地图,因为我目前正在尝试完成一个编码挑战,其中输入以我的地图格式提供给我。如果这是非法/不一致的语法,我该如何处理这样的输入?
  • @J.Doe 这不是非法语法,它基本上不是类型安全的(您的地图包含 String -> Any)。所以为了使用它,你必须像'asInstanceOf'那样进行类型转换。但它通常更容易出错,因为编译器无法帮助你。我认为,对于您的挑战,可以这样做。
【解决方案3】:

你可以试试这个,

val l = List(Map("startlocation" -> "Kruthika's abode", "endlocation" -> "Mark's crib", "distance" -> 10), 
            Map("startlocation" -> "Mark's Crib", "endlocation" -> "Kirk's Farm", "distance" -> 9));

case class Node(visited:Boolean = false, mDistance:Int = 10000, prevLoc:String)

l.map(x=>Node(prevLoc = x("startlocation").asInstanceOf[String]))

【讨论】:

  • +1 因为它建议 case class Nodel.map +1 因为它是在我之前发布的 -1 因为它建议 .asInstanceOf 给 scala 新人。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-14
  • 1970-01-01
  • 1970-01-01
  • 2021-04-01
  • 2023-03-15
  • 1970-01-01
  • 2018-08-22
相关资源
最近更新 更多