2012-03-05 12 views
5

ArrayBufferの一部をシャッフルする必要があります。コピーは不要です。 ArrayBufferは、10個の要素を持っている、と私は要素3-7をシャッフルしたい場合たとえば、:ArrayBufferの一部をシャッフルする

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

GoogleでArrayBufferを部分的にシャッフルすることについては何も見つかりませんでした。私は自分の方法を書かなければならないと考えていますが、そうすることでコピーを防止したいと思います。

答えて

3

私はそれがなぜ必要なのか完全にはわかりません。しかし、これはそれを行うことができ、それが行うには正しいことだと仮定すると:

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

は編集:あなたは余分なコストを支払うことを喜んでいる場合

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

あなたが持っているものを使うと、私はこれを得ます: '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) '。実際には何もシャッフルしていないようです。 –

+0

複数回試してみてください。それは所定の位置にシャッフルしているので、あなたの考え方(実際は単純です)では機能しません。 't._1'と' t._2'を常に交換するのではなく、動いているものが動いて動いているもののいくつかはすでに移動されています。それを気軽に改善してください。 –

+0

私は、それが2回目の呼び出しの後にシャッフルしたことを確認します。唯一の問題は、開始と終了の両方を1ずつ減らす必要があることです。なぜなら、shufflePart(2、7)を使用すると、シャッフルが3-8になるからです。また、 'seq'にshuffleを使うことで、そこにコピーが作成されている可能性がまだあります。たぶん私はコピーの問題を考えすぎています。 –

5

あなたは根本的な配列にアクセスすることができますArrayBufferのサブタイプを使用することができた場合:中間シーケンスは、これはアルゴリズム的に言えば、より合理的です

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は、要素の新しいセットを作成していないので、それは合理的に効率的です:直接、ResizableArrayので、保護されたメンバーarrayを持っています配列自体によってサポートされています(したがって、メソッドの追加や削除はありません)
  • 実際に使用する場合は、aと012に境界チェックを追加することをお勧めします
関連する問題