【问题标题】:How to declare empty list and then add string in scala?如何声明空列表然后在scala中添加字符串?
【发布时间】:2011-09-27 06:46:10
【问题描述】:

我有这样的代码:

val dm  = List[String]()
val dk = List[Map[String,Object]]()

.....

dm.add("text")
dk.add(Map("1" -> "ok"))

但它会抛出运行时 java.lang.UnsupportedOperationException。

我需要声明空列表或空地图,并且在代码后面的一些地方需要填充它们。

【问题讨论】:

  • 是什么让你认为List 上存在add 操作?
  • 如果你想使用add操作,你必须声明一个ArrayList。 scala 中的 Vals 本质上是不可变的,所以你不能添加它们。
  • iirc val 更像是 final,如果你使用可变集合,你可以添加到它们。例如scala-lang.org/api/current/scala/collection/mutable/…
  • @rjc 你用的是哪个版本的scala?我的(2.9.0)给了我一个编译错误。
  • 你导入scala.collection.JavaConversions了吗?如果你这样做了,你就会看到我推荐 JavaConverters 的原因:dmdk 正在被转换为 Java 集合,然后在该集合上调用 add 方法。更糟糕的是,dmdk 没有被修改,即使您没有收到错误。而且,顺便说一句,错误是1 -> "ok"Map[Int,String],而不是Map[String, Object]

标签: scala


【解决方案1】:

Scala 列表默认是不可变的。您不能“添加”一个元素,但可以通过在前面附加新元素来形成一个新列表。由于它是一个 new 列表,因此您需要重新分配引用(因此您不能使用 val)。

var dm  = List[String]()
var dk = List[Map[String,AnyRef]]()

.....

dm = "text" :: dm
dk = Map(1 -> "ok") :: dk

运算符:: 创建新列表。您也可以使用较短的语法:

dm ::= "text" 
dk ::= Map(1 -> "ok")

注意:在 scala 中不要使用 Object 类型,而是使用 AnyAnyRefAnyVal

【讨论】:

  • 很好的答案,但你能告诉我如果我在你的答案中声明列表,它们是 scala.collections.mutable 类型还是不可变类型? REPL 没有说清楚。
  • 默认情况下。如果你什么都不进口。 List 是不可变的。这是大多数情况下推荐的。
  • @rjc Scala 没有mutable.List -- List 是一个具体类型,其中唯一的实现是不可变的。有LinkedListDoubleLinkedList等不可变类,主要是辅助类。 Java 的ArrayList 的Scala 等价物是ArrayBuffer,Java 的LinkedList 的等价物是ListBuffer。对应于 Java 的 List 的 trait 是 Seq —— 其中有 collection.Seq 和扩展它,collection.immutable.Seqcollection.mutable.Seq
  • @paradigmatic ::=+= 之间有区别吗?
  • @Mahdi 可能有所不同。在列表中,仅定义了 ::,因此 += 将不起作用。在其他集合上(不在标准库中):如果实现了::=+=,则将使用该实现。否则,编译器会将x::=y 转换为x = y::xx+=y inro x=x+y。在第二种情况下,如果::的实现与+的实现相同,则它们是相同的...
【解决方案2】:

如果您需要改变内容,请改用ArrayBufferLinkedBuffer。但是,最好解决此声明:

我需要声明空列表或为空 地图和代码后面的一些地方 需要填写。

不要这样做,而是用返回元素的代码填充列表。有很多方法可以做到这一点,我会举一些例子:

// Fill a list with the results of calls to a method
val l = List.fill(50)(scala.util.Random.nextInt)

// Fill a list with the results of calls to a method until you get something different
val l = Stream.continually(scala.util.Random.nextInt).takeWhile(x => x > 0).toList

// Fill a list based on its index
val l = List.tabulate(5)(x => x * 2)

// Fill a list of 10 elements based on computations made on the previous element
val l = List.iterate(1, 10)(x => x * 2)

// Fill a list based on computations made on previous element, until you get something
val l = Stream.iterate(0)(x => x * 2 + 1).takeWhile(x => x < 1000).toList

// Fill list based on input from a file
val l = (for (line <- scala.io.Source.fromFile("filename.txt").getLines) yield line.length).toList

【讨论】:

    【解决方案3】:

    正如大家已经提到的,这不是在 Scala 中使用列表的最佳方式...

    scala> val list = scala.collection.mutable.MutableList[String]()
    list: scala.collection.mutable.MutableList[String] = MutableList()
    
    scala> list += "hello"
    res0: list.type = MutableList(hello)
    
    scala> list += "world"
    res1: list.type = MutableList(hello, world)
    
    scala> list mkString " "
    res2: String = hello world
    

    【讨论】:

    • 您能否判断您的列表是否像您的答案一样声明,与范式回答相比,它会提供更好的运行时性能吗?假设将在列表中添加数百万个元素。
    • 这取决于您要达到的目标。正如@paradigmatic 所建议的那样,我建议从一个不可变的开始。像这样将元素添加到不可变列表的复杂性:list ::= "text" 是 O(1),它是恒定的,是你能做的最好的。
    • rjc:不可变列表的缺点是 O(1);但是,就效率而言,真正重要的是您的访问模式。例如,如果顺序很重要并且您必须通过附加来构建列表,则 Vector 是更好的(不可变的)选择。
    【解决方案4】:

    正如上面answer 中提到的,Scala List 是一个不可变集合。您可以使用 .empty[A] 创建一个空列表。然后您可以使用:++::: 方法将元素添加到列表中。

    scala> val strList = List.empty[String]
    strList: List[String] = List()
    
    scala> strList:+ "Text"
    res3: List[String] = List(Text)
    
    scala> val mapList = List.empty[Map[String, Any]]
    mapList: List[Map[String,Any]] = List()
    
    scala> mapList :+ Map("1" -> "ok")
    res4: List[Map[String,Any]] = List(Map(1 -> ok))
    

    【讨论】:

      【解决方案5】:

      scala 中的默认集合是不可变的,所以你有一个 + 方法,它返回一个新列表,其中添加了元素。 如果你真的需要像 add 方法这样的东西,你需要一个可变集合,例如http://www.scala-lang.org/api/current/scala/collection/mutable/MutableList.html 有一个 += 方法。

      【讨论】:

        【解决方案6】:

        也许您可以在 scala 中使用 ListBuffers 创建空列表并稍后添加字符串,因为 ListBuffers 是可变的。 scala 中的 ListBuffers 也可以使用所有 List 函数。

        import scala.collection.mutable.ListBuffer 
        
        val dm = ListBuffer[String]()
        dm: scala.collection.mutable.ListBuffer[String] = ListBuffer()
        dm += "text1"
        dm += "text2"
        dm = ListBuffer(text1, text2)
        

        如果您愿意,可以使用 .toList 将其转换为列表

        【讨论】:

          【解决方案7】:

          在你的情况下,我使用:val dm = ListBuffer[String]()val dk = ListBuffer[Map[String,anyRef]]()

          【讨论】:

            猜你喜欢
            • 2017-09-11
            • 1970-01-01
            • 2021-06-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-12-23
            相关资源
            最近更新 更多