【问题标题】:Appending an element to the end of a list in Scala在Scala中将元素附加到列表的末尾
【发布时间】:2011-10-17 12:56:34
【问题描述】:

我无法将T 类型的元素添加到列表List[T] 中。 我尝试使用myList ::= myElement,但它似乎创建了一个奇怪的对象,并且访问myList.last 总是返回放入列表中的第一个元素。我该如何解决这个问题?

【问题讨论】:

    标签: arrays scala


    【解决方案1】:
    List(1,2,3) :+ 4
    
    Results in List[Int] = List(1, 2, 3, 4)
    

    请注意,此操作的复杂度为 O(n)。如果您经常需要此操作,或者对于长列表,请考虑使用其他数据类型(例如 ListBuffer)。

    【讨论】:

    • 没有 O(2*n),对于渐近复杂度,常数因子被忽略。我认为List 被转换为ListBuffer,元素被附加,ListBuffer 被转换回来(很像Java 中的StringStringBuilder),但这只是一个猜测。
    • 这是 O(n),因为您必须完全遍历列表才能到达最后一个元素指针并能够附加元素使最后一个元素指针指向它。
    • @pisaruk 如果是这样的话,可以只维护一个指向头部和尾部的指针。但是,list in scala 是不可变的,这意味着要“修改”列表的最后一个元素,需要先对其进行复制。它的副本是 O(n) - 不是列表本身的遍历。
    • 我相信它是 O(n) 仅仅是因为创建了一个全新的列表
    • cons 运算符的复杂度为 O(1),因为它适用于列表的“预期”一侧。
    【解决方案2】:

    那是因为您不应该这样做(至少对于不可变列表)。 如果你真的需要在数据结构的末尾添加一个元素,并且这个数据结构真的需要是一个列表,而且这个列表真的必须是不可变的,那么请执行以下操作:

    (4 :: List(1,2,3).reverse).reverse
    

    或者那个:

    List(1,2,3) ::: List(4)
    

    【讨论】:

    • 非常感谢!这正是我正在寻找的。我从你的回答中猜想我不应该这样做......我会修改我的结构,看看我能做什么。再次感谢。
    • @Masar 如果您想要不变性和高效附加,请使用 Vector。请参阅scala-lang.org/docu/files/collections-api/collections.html中的性能特征部分
    • 如果您要添加许多元素,“通过前置然后反转它来构建列表”是一种有用的模式,但我认为像在将单个元素添加到现有列表的情况。 “双重反向”技巧将列表重建两次,而:+ 可能效率低下,只重建一次。
    【解决方案3】:

    Scala 中的列表不是为修改而设计的。事实上,你不能在 Scala List 中添加元素;它是一个不可变的数据结构,类似于 Java 字符串。 当您在 Scala 中“将元素添加到列表”时,您实际上所做的是从现有列表中创建一个 新列表(Source)

    我建议不要使用列表来处理此类用例,而是使用ArrayBufferListBuffer。这些数据结构旨在添加新元素。

    最后,完成所有操作后,缓冲区就可以转换为列表了。请参阅以下 REPL 示例:

    scala> import scala.collection.mutable.ListBuffer
    import scala.collection.mutable.ListBuffer
    
    scala> var fruits = new ListBuffer[String]()
    fruits: scala.collection.mutable.ListBuffer[String] = ListBuffer()
    
    scala> fruits += "Apple"
    res0: scala.collection.mutable.ListBuffer[String] = ListBuffer(Apple)
    
    scala> fruits += "Banana"
    res1: scala.collection.mutable.ListBuffer[String] = ListBuffer(Apple, Banana)
    
    scala> fruits += "Orange"
    res2: scala.collection.mutable.ListBuffer[String] = ListBuffer(Apple, Banana, Orange)
    
    scala> val fruitsList = fruits.toList
    fruitsList: List[String] = List(Apple, Banana, Orange)
    

    【讨论】:

      【解决方案4】:

      这类似于其中一个答案,但方式不同:

      scala> val x = List(1,2,3)
      x: List[Int] = List(1, 2, 3)
      
      scala> val y = x ::: 4 :: Nil
      y: List[Int] = List(1, 2, 3, 4)
      

      【讨论】:

        【解决方案5】:

        我们可以追加或前置两个列表或列表和数组
        追加:

        var l = List(1,2,3)    
        l = l :+ 4 
        Result : 1 2 3 4  
        var ar = Array(4, 5, 6)    
        for(x <- ar)    
        { l = l :+ x }  
          l.foreach(println)
        
        Result:1 2 3 4 5 6
        

        前置:

        var l = List[Int]()  
           for(x <- ar)  
            { l= x :: l } //prepending    
             l.foreach(println)   
        
        Result:6 5 4 1 2 3
        

        【讨论】:

        • 是的,我们可以,但由于其他答案中提到的所有原因,这将是一个坏主意。
        猜你喜欢
        • 2018-04-08
        • 2012-09-12
        • 1970-01-01
        • 1970-01-01
        • 2017-06-23
        • 1970-01-01
        • 2014-06-10
        • 1970-01-01
        • 2020-09-02
        相关资源
        最近更新 更多