Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shuffling part of an ArrayBuffer in-place

I need to shuffle part of an ArrayBuffer, preferably in-place so no copies are required. For example, if an ArrayBuffer has 10 elements, and I want to shuffle elements 3-7:

// Unshuffled ArrayBuffer of ints numbered 0-9
0, 1, 2, 3, 4, 5, 6, 7, 8, 9

// Region I want to shuffle is between the pipe symbols (3-7)
0, 1, 2 | 3, 4, 5, 6, 7 | 8, 9

// Example of how it might look after shuffling
0, 1, 2 | 6, 3, 5, 7, 4 | 8, 9

// Leaving us with a partially shuffled ArrayBuffer
0, 1, 2, 6, 3, 5, 7, 4, 8, 9

I've written something like shown below, but it requires copies and iterating over loops a couple of times. It seems like there should be a more efficient way of doing this.

def shufflePart(startIndex: Int, endIndex: Int) {

  val part: ArrayBuffer[Int] = ArrayBuffer[Int]()

  for (i <- startIndex to endIndex ) {
    part += this.children(i)
  }

  // Shuffle the part of the array we copied
  val shuffled = this.random.shuffle(part)
  var count: Int = 0

  // Overwrite the part of the array we chose with the shuffled version of it
  for (i <- startIndex to endIndex ) {
    this.children(i) = shuffled(count)
    count += 1
  }
}

I could find nothing about partially shuffling an ArrayBuffer with Google. I assume I will have to write my own method, but in doing so I would like to prevent copies.

like image 415
Nic Foster Avatar asked Mar 05 '12 19:03

Nic Foster


1 Answers

If you can use a subtype of ArrayBuffer you can access the underlying array directly, since ResizableArray has a protected member array:

import java.util.Collections
import java.util.Arrays
import collection.mutable.ArrayBuffer


val xs = new ArrayBuffer[Int]() {
  def shuffle(a: Int, b: Int) {
    Collections.shuffle(Arrays.asList(array: _*).subList(a, b))
  }
}

xs ++= (0 to 9)    // xs = ArrayBuffer(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
xs.shuffle(3, 8)   // xs = ArrayBuffer(0, 1, 2, 4, 6, 5, 7, 3, 8, 9)

Notes:

  • The upper bound for java.util.List#subList is exclusive
  • It's reasonably efficient because Arrays#asList doesn't create a new set of elements: it's backed by the array itself (hence no add or remove methods)
  • If using for real, you probably want to add bounds-checks on a and b
like image 134
Luigi Plinge Avatar answered Sep 20 '22 08:09

Luigi Plinge