stella
stella

Reputation: 2596

Prepending to ArraySeq without copying it

In the documentation of +: method in ArraySeq said that

A copy of the sequence with an element prepended.

Is there a way to prepend an element without copying the whole ArraySeq?

Upvotes: 1

Views: 697

Answers (3)

Ram Ghadiyaram
Ram Ghadiyaram

Reputation: 29155

This is how ArraySeq works. AFAIK there is no other built in option available.

Means, to adjust the size it has to return new copy :(

  scala> val a = List(1)
    a: List[Int] = List(1)

scala> val b = a :+ 2
b: List[Int] = List(1, 2)

scala> println(a)
List(1)

Doc says:

abstract def +:(elem: A): ArraySeq[A] [use case] A copy of the array sequence with an element prepended. elem the prepended element returns a new collection of type That consisting of elem followed by all elements of this array sequence. Definition Classes GenSeqLike

Similar function is there in ArrayBuffer as well. It also copies to create new one. Below are the snippets for better understanding...

snippet 1:

/** Prepends a single element to this buffer and returns
   *  the identity of the buffer. It takes time linear in 
   *  the buffer size.
   *
   *  @param elem  the element to append.
   *  @return      the updated buffer. 
   */
  def +=:(elem: A): this.type = {
    ensureSize(size0 + 1)
    copy(0, 1, size0)
    array(0) = elem.asInstanceOf[AnyRef]
    size0 += 1
    this
  }

Snippet2:

/** Inserts new elements at the index `n`. Opposed to method
   *  `update`, this method will not replace an element with a
   *  one. Instead, it will insert a new element at index `n`.
   *  
   *  @param n     the index where a new element will be inserted.
   *  @param seq   the traversable object providing all elements to insert.
   *  @throws Predef.IndexOutOfBoundsException if `n` is out of bounds.
   */
  def insertAll(n: Int, seq: Traversable[A]) {
    if (n < 0 || n > size0) throw new IndexOutOfBoundsException(n.toString)
    val xs = seq.toList
    val len = xs.length
    ensureSize(size0 + len)
    copy(n, n + len, size0 - n)
    xs.copyToArray(array.asInstanceOf[scala.Array[Any]], n)
    size0 += len
  }

Upvotes: 1

Samar
Samar

Reputation: 2101

Even though ArraySeq is a mutable collection, certain member methods of this collection will return a copy of the collection and not do "in place" transformation. From the scala doc collections overview

A collection in package scala.collection.mutable is known to have some operations that change the collection in place. So dealing with mutable collection means you need to understand which code changes which collection when.

So, its possible that mutable collections will have some methods that will return copies of the original collection.

On the other hand, its guaranteed that all operations on collections in the scala.collection.immutable package will return copies of the original collection.

Upvotes: 1

J&#246;rg W Mittag
J&#246;rg W Mittag

Reputation: 369430

You can't. Quoting from the Collections Overview (bold emphasis mine):

Array sequences are mutable sequences of fixed size which store their elements internally in an Array[Object]. They are implemented in Scala by class ArraySeq.

Prepending changes the size, ergo it is not possible to prepend to an ArraySeq.

They are very similar to Arrays, which are of course also mutable and have a fixed size.

If you want to change the size, you need a *Builder or a *Buffer, in this case, an ArrayBuffer, which does have a +=: method for prepending.

Upvotes: 1

Related Questions