B3th4 B3th4 - 10 days ago 7
Scala Question

ArrayBuffer of Array += not working as expected

def produced(sol:Array[Int]):Array[Array[Int]]={
println("hello")
val buf = scala.collection.mutable.ArrayBuffer.empty[Array[Int]]
var productAtTime = Array.fill[Int](NumItem)(0)
var z=0
while(z<NumPeriod){
var x =sol(z)
if(x != -1){
productAtTime(x)=productAtTime(x)+1
println(productAtTime.mkString)
buf+=productAtTime
var arraybuf= buf.toArray
println(arraybuf.deep.mkString)
}
else{
buf+=productAtTime
}
z+=1
}
return buf.toArray
}


I'm trying to create an Array using an ArrayBuffer. Each element of this ArrayBuffer is an array. Each element should be the same as the previous one, except for at most one element that should be incremented by one. (no incrementation if sol(z)=-1, else there is one)

So for each z from 0 to NumPeriod I create an Array based on the previous one, and I would like to append this array to my buffer. For some reason, the array that is appended also replaces all the previous arrays in the buffer by itself.

ex. output of the prints I get: for sol= (1,1,-1,0,0)

hello
01
Array(0, 1)
02
Array(0, 2)Array(0, 2)
12
Array(1, 2)Array(1, 2)Array(1, 2)Array(1, 2)
22
Array(2, 2)Array(2, 2)Array(2, 2)Array(2, 2)Array(2, 2)


As can be seen, the array that has to be appended exist but during the += it also changes all the previous arrays that are in the ArrayBuffer.
I would like something like:

hello
01
Array(0, 1)
02
Array(0, 1)Array(0, 2)
12
Array(0, 1)Array(0, 2)Array(0, 2)Array(1, 2)
22
Array(0, 1)Array(0, 2)Array(0, 2)Array(1, 2)Array(2, 2)

Answer

You're referencing (pointing to) the same Array[Int] each time inside your Array[Array[Int]], that's why you're seeing the same values repeated. You need to allocate a new array on each iteration. You can do this via Array[T].clone:

$ scala
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_91).
Type in expressions for evaluation. Or try :help.

scala> :pa
// Entering paste mode (ctrl-D to finish)

def produced(sol: Array[Int]): Array[Array[Int]] = {
  val NumItem = 2
  val NumPeriod = 5

  println("hello")
  val buf = scala.collection.mutable.ArrayBuffer.empty[Array[Int]]
  var productAtTime: Array[Int] = Array.fill[Int](NumItem)(0)
  var z = 0
  while (z < NumPeriod) {
    val x = sol(z)
    if (x != -1) {
      productAtTime(x) = productAtTime(x) + 1
      println(productAtTime.mkString)
      buf += productAtTime.clone()
      val arraybuf = buf.toArray
      println(arraybuf.deep.mkString)
    }
    else {
      buf += productAtTime.clone()
    }
    z += 1
  }
  buf.toArray
}

// Exiting paste mode, now interpreting.

produced: (sol: Array[Int])Array[Array[Int]]

scala> produced(Array(1, 1, -1, 0, 0))
hello
01
Array(0, 1)
02
Array(0, 1)Array(0, 2)
12
Array(0, 1)Array(0, 2)Array(0, 2)Array(1, 2)
22
Array(0, 1)Array(0, 2)Array(0, 2)Array(1, 2)Array(2, 2)
res1: Array[Array[Int]] = Array(Array(0, 1), Array(0, 2), Array(0, 2), Array(1, 2), Array(2, 2))