2012-03-05 7 views
5

Necesito mezclar parte de un ArrayBuffer, preferiblemente en el lugar, por lo que no se requieren copias. Por ejemplo, si un ArrayBuffer tiene 10 elementos, y quiero mezclar elementos 3-7:Mezclar parte de un ArrayBuffer en contexto

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

que he escrito algo como se muestra a continuación, pero requiere de copias y la iteración en bucles de un par de veces. Parece que debería haber una manera más eficiente de hacer esto.

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

No pude encontrar nada acerca de mezclar parcialmente un ArrayBuffer con Google. Supongo que tendré que escribir mi propio método, pero al hacerlo me gustaría evitar copias.

Respuesta

3

No estoy del todo seguro de por qué debe estar en su lugar, es posible que desee pensar en eso. Sin embargo, asumiendo que es lo que hay que hacer, esto podría hacerlo:

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

Usted puede usarlo como:

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

edición: Si usted está dispuesto a pagar el coste adicional de una secuencia intermedia, esto es más razonable, hablando de forma algorítmica:

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

Cuando uso lo que tiene consigo este: 'ArrayBuffer (1, 2, 3, 4, 5, 6, 7, 8, 9); ArrayBuffer (1, 2, 3, 4, 5, 6, 7, 8, 9); a: scala.collection.mutable.ArrayBuffer [Int] = ArrayBuffer (1, 2, 3, 4, 5, 6, 7, 8, 9) '. Parece que en realidad no baraja nada. –

+0

Pruébalo más de una vez. Debido a que está arrastrando los pies en su lugar, no funciona de la forma en que piensas (es realmente simple). No intercambia 't._1' con' t._2' todo el tiempo, ya que mueve las cosas como va y algunas de las cosas que mueve ya se han movido. Siéntase libre de mejorarlo. –

+0

Ya veo, sí, se mezcló después de la segunda llamada. El único problema es que tanto el inicio como el final deben reducirse en uno, porque el uso de shufflePart (2, 7) hace que se mezcle 3-8. Además, al usar shuffle en 'seq', aún es probable que se realice una copia allí mismo. Tal vez estoy pensando demasiado sobre el tema de la copia. –

5

Si puede utilizar un subtipo de ArrayBuffer se puede acceder a la matriz subyacente miembro directamente, ya que ResizableArray tiene una protegida 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) 

Notas:

  • El límite superior para java.util.List#subList es exclusiva
  • Es razonablemente eficiente porque Arrays#asList no crea un nuevo conjunto de elementos: está respaldado por la matriz misma (de ahí que no se agreguen o eliminen métodos)
  • Si se usa de forma real, es probable que desee agregar límites-cheques en a y b