Scala prepend如何保持列表的不变性,而append如何不保持?

Scala prepend如何保持列表的不变性,而append如何不保持?,scala,immutability,Scala,Immutability,如果我们将一个元素附加到一个列表中,那么如何在Scala中保持列表的不变性呢?难道不应该列一份新的清单吗?在java中,如果您添加一个字母作为第一个字符,那么将生成一个新字符串,并且字符串在java中是不可变的。在Scala中,追加是线性时间的原因是什么?是遍历整个列表并在末尾添加,还是线性的,因为我们需要在更改对象后创建一个全新的列表 在列表前加和追加都会产生一个新的列表,从而保持列表的不变性。我们可以这样检查 val l = List(1) l.prepended(0) l.appended

如果我们将一个元素附加到一个列表中,那么如何在Scala中保持列表的不变性呢?难道不应该列一份新的清单吗?在java中,如果您添加一个字母作为第一个字符,那么将生成一个新字符串,并且字符串在java中是不可变的。在Scala中,追加是线性时间的原因是什么?是遍历整个列表并在末尾添加,还是线性的,因为我们需要在更改对象后创建一个全新的列表

列表
前加和追加都会产生一个新的
列表
,从而保持
列表
的不变性。我们可以这样检查

val l = List(1)
l.prepended(0)
l.appended(2)
l             // just has List(1) instead of List(0,1,2)
Prepend是常量时间,因为它不会复制整个列表。相反,它只是创建一个新对象,其中包含对新头部的引用和对前一个尾部的引用

def prepended[B >: A](elem: B): List[B] = elem :: this   // new ::(elem, this)
Append是线性时间,因为它复制整个列表

def appended[B >: A](elem: B): CC[B] = {
  val b = iterableFactory.newBuilder[B]
  ...
  b ++= this  // copy of the entire list happens here
  b += elem
  b.result()
}
另请注意,检索
列表
的最后一个元素是线性时间,因为
列表
实现为单链接列表,因此它不知道最后一个元素的引用


对于注释,列表可以是一种有效的结构,尽管返回了新的
List
,只要您以前置方式正确使用它。有时,您必须
反转末尾的列表以获得所需的顺序,但这是一次性遍历。绩效最终应在特定情况下通过sbt jmh进行衡量


还要注意不要将
数组
列表
混淆。前者并不是真正的Scala集合

implicitly[Array[Int] <:< Iterable[Int]] // error

隐式[Array[Int]在
列表
前加和后加都会产生一个新的
列表
,从而保持
列表
的不变性

val l = List(1)
l.prepended(0)
l.appended(2)
l             // just has List(1) instead of List(0,1,2)
Prepend是常量时间,因为它不复制整个列表,而是创建一个新对象,该对象包含对新头部的引用和对前一个尾部的引用

def prepended[B >: A](elem: B): List[B] = elem :: this   // new ::(elem, this)
Append是线性时间,因为它复制整个列表

def appended[B >: A](elem: B): CC[B] = {
  val b = iterableFactory.newBuilder[B]
  ...
  b ++= this  // copy of the entire list happens here
  b += elem
  b.result()
}
另请注意,检索
列表
的最后一个元素是线性时间,因为
列表
实现为单链接列表,因此它不知道最后一个元素的引用


针对注释,列表可以是一种有效的结构,尽管返回了新的
列表
,只要您以前置方式正确使用它。有时您必须
将列表反向
以获得所需的顺序,但这是一次性的遍历。性能最终应在pa内进行测量例如,sbt jmh的关节情况


还要注意不要将
数组
列表
混淆。前者不是真正的Scala集合

implicitly[Array[Int] <:< Iterable[Int]] // error

隐式[Array[Int]谁说追加没有?是的,这是线性的,因为你说的原因。谁说追加没有?是的,它是线性的,因为你说的原因。谢谢你的回答。有没有可能找到创建新数组的时间复杂性,因为每一次更改都会产生新的数组?@Victorman你对数组和导致新数组的更改是什么意思新的一个?“添加到
列表
是线性时间,因为
列表
是作为单个链接列表实现的,因此它不知道最后一个元素的引用。”–IMO更相关的原因是它是线性的,因为它需要复制整个列表,这意味着它不仅具有线性最坏情况下的步骤复杂性,还具有线性最坏情况下的空间复杂性。或者更旧的,谢谢您的回答。是否可以找到创建新数组的时间复杂性,因为每次更改都会产生新的数组?@livitman你对数组和导致新元素的更改是什么意思?“
列表
的附加是线性时间,因为
列表
是作为单个链接列表实现的,因此它不知道最后一个元素的引用。”–the(IMO)它是线性的更相关的原因是它需要复制整个列表,这意味着它不仅具有线性最坏情况下的步骤复杂性,还具有线性最坏情况下的空间复杂性