Перемешивание части ArrayBuffer на месте - PullRequest
5 голосов
/ 05 марта 2012

Мне нужно перетасовать часть ArrayBuffer, желательно на месте, поэтому никаких копий не требуется. Например, если ArrayBuffer имеет 10 элементов, и я хочу перетасовать элементы 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

Я написал что-то вроде показанного ниже, но это требует копий и повторения циклов пару раз. Кажется, должен быть более эффективный способ сделать это.

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
  }
}

Я не мог найти ничего о частичной перетасовке ArrayBuffer с Google. Я предполагаю, что мне придется написать свой собственный метод, но при этом я бы хотел предотвратить копирование.

Ответы [ 2 ]

5 голосов
/ 06 марта 2012

Если вы можете использовать подтип ArrayBuffer, вы можете получить доступ к базовому массиву напрямую, поскольку ResizableArray имеет защищенный член 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)

Примечания:

  • Верхняя граница для java.util.List#subList является исключительной
  • Это достаточно эффективно, потому что Arrays#asList не создает новый набор элементов: он поддерживается самим массивом (следовательно, нет методов добавления и удаления)
  • Если вы используете по-настоящему, вы, вероятно, захотите добавить проверки границ для a и b
3 голосов
/ 05 марта 2012

Я не совсем уверен, почему это должно быть на месте - вы можете подумать об этом. Но, предполагая, что это правильно, это может сделать это:

import scala.collection.mutable.ArrayBuffer

implicit def array2Shufflable[T](a: ArrayBuffer[T]) = new {
  def shufflePart(start: Int, end: Int) = {
    val seq = (start.max(0) until end.min(a.size - 1)).toSeq
    seq.zip(scala.util.Random.shuffle(seq)) foreach { t =>
      val x = a(t._1)
      a.update(t._1, a(t._2))
      a(t._2) = x
    }
    a
  }
}

Вы можете использовать его как:

val a = ArrayBuffer(1,2,3,4,5,6,7,8,9)
println(a)
println(a.shufflePart(2, 7))  

edit : Если вы готовы оплатить дополнительную стоимость промежуточной последовательности, это более разумно, если говорить алгоритмически:

  def shufflePart(start: Int, end: Int) = {
    val seq = (start.max(0) until end.min(a.size - 1)).toSeq
    seq.zip(scala.util.Random.shuffle(seq) map { i =>
      a(i)
    }) foreach { t =>
      a.update(t._1, t._2)
    }
    a
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...