11

ランダムに並べ替えたい配列があります。Java には、List の要素をランダムにシャッフルできる Collections.shuffle() メソッドがあります。配列でも使用できます。

String[] array = new String[]{"a", "b", "c"};

// Shuffle the array; works because the list returned by Arrays.asList() is backed by the array
Collections.shuffle(Arrays.asList(array));

これを Scala 配列で使用しようとしましたが、Scala インタープリターは長い回答で応答します。

scala> val a = Array("a", "b", "c")
a: Array[java.lang.String] = Array(a, b, c)

scala> java.util.Collections.shuffle(java.util.Arrays.asList(a))
<console>:6: warning: I'm seeing an array passed into a Java vararg.
I assume that the elements of this array should be passed as individual arguments to the vararg.
Therefore I follow the array with a `: _*', to mark it as a vararg argument.
If that's not what you want, compile this file with option -Xno-varargs-conversion.
       java.util.Collections.shuffle(java.util.Arrays.asList(a))
                                                             ^
<console>:6: error: type mismatch;
 found   : Array[java.lang.String]
 required: Seq[Array[java.lang.String]]
       java.util.Collections.shuffle(java.util.Arrays.asList(a))
                                                             ^

ここで正確に何が起こっているのですか?このため、特別なフラグ (-Xno-varargs-conversion) を使用してコードをコンパイルしたくありません。

では、Scala 配列で Java の Collections.shuffle() を使用するにはどうすればよいでしょうか?

その間、Scala で独自のシャッフル メソッドを作成しました。

// Fisher-Yates shuffle, see: http://en.wikipedia.org/wiki/Fisher–Yates_shuffle
def shuffle[T](array: Array[T]): Array[T] = {
    val rnd = new java.util.Random
    for (n <- Iterator.range(array.length - 1, 0, -1)) {
        val k = rnd.nextInt(n + 1)
        val t = array(k); array(k) = array(n); array(n) = t
    }
    return array
}

配列をその場でシャッフルし、利便性のために配列自体を返します。

4

3 に答える 3

6
java.util.Collections.shuffle(java.util.Arrays.asList(a:_*))

上記が正しく機能するためには、Arrays.asList()が結果java.utilのバッキングストアとして渡された配列を使用するため、の要素タイプはscala.AnyRef(java.lang.Objectと同等)のサブクラスである必要があります。 Listとjava.util.Listには、オブジェクト参照のみを含めることができます(プリミティブ値は含めることができません)。*

これが、渡されたjava.util.ListをシャッフルするCollections.shuffle()が実際に配列をシャッフルした理由でもあります。*

*:以下の注を参照してください

例えば:

scala> val a = Array[java.lang.Integer](1, 2, 3) // note the type parameter                  
a: Array[java.lang.Integer] = Array(1, 2, 3)

scala> java.util.Collections.shuffle(java.util.Arrays.asList(a:_*))

scala> a
res43: Array[java.lang.Integer] = Array(1, 3, 2)

scala> java.util.Collections.shuffle(java.util.Arrays.asList(a:_*))

scala> a
res45: Array[java.lang.Integer] = Array(1, 2, 3)

注:上記のコードスニペットにはScala2.7.5が使用されています。Scala 2.8.0は、Danielが示したようにさまざまな動作を示します。安全のために、配列がシャッフルされるという事実に依存せず、代わりにArrays.asList()から返されるリストがシャッフルされます。

scala> val a = Array[java.lang.Integer](1, 2, 3)
a: Array[java.lang.Integer] = Array(1, 2, 3)

scala> val b = java.util.Arrays.asList(a:_*)
b: java.util.List[java.lang.Integer] = [1, 2, 3]

scala> java.util.Collections.shuffle(b)

scala> b
res50: java.util.List[java.lang.Integer] = [2, 1, 3]

scala> java.util.Collections.shuffle(b)

scala> b
res52: java.util.List[java.lang.Integer] = [3, 1, 2]
于 2009-08-11T09:37:23.087 に答える
6

可変引数に関しては、Scala は Java とは異なることをしているようです。少なくとも、どうやってもその配列をシャッフルすることはできません。おそらく、リストは配列に裏打ちされているため、リストのシャッフルは配列をシャッフルします。さて、Scala はvararg 引数を Java に渡すときに新しい配列を作成するように思われるため、前述の例は役に立たなくなります。

scala> val b = java.util.Arrays.asList(a: _*)
b: java.util.List[java.lang.String] = [a, b, c]

scala> java.util.Collections.shuffle(b); println(a.toString+" "+b.toString)
Array(a, b, c) [a, b, c]

scala> java.util.Collections.shuffle(b); println(a.toString+" "+b.toString)
Array(a, b, c) [c, b, a]

scala> java.util.Collections.shuffle(b); println(a.toString+" "+b.toString)
Array(a, b, c) [a, c, b]

scala> java.util.Collections.shuffle(b); println(a.toString+" "+b.toString)
Array(a, b, c) [b, a, c]

scala> java.util.Collections.shuffle(b); println(a.toString+" "+b.toString)
Array(a, b, c) [a, b, c]

scala> java.util.Collections.shuffle(b); println(a.toString+" "+b.toString)
Array(a, b, c) [c, a, b]

ただし、それ以外の主張にもかかわらず、Ints で動作します。

scala> val a = Array(1,2,3)
a: Array[Int] = Array(1, 2, 3)

scala> val b = java.util.Arrays.asList(a: _*)
b: java.util.List[Int] = [1, 2, 3]

scala> java.util.Collections.shuffle(b); println(a.toString+" "+b.toString)
Array(1, 2, 3) [2, 3, 1]

scala> java.util.Collections.shuffle(b); println(a.toString+" "+b.toString)
Array(1, 2, 3) [3, 2, 1]

scala> java.util.Collections.shuffle(b); println(a.toString+" "+b.toString)
Array(1, 2, 3) [3, 2, 1]

scala> java.util.Collections.shuffle(b); println(a.toString+" "+b.toString)
Array(1, 2, 3) [1, 2, 3]

Scala 2.8 では、より簡単な方法があります。

scala> scala.util.Random.shuffle(a)
res32: Sequence[Int] = Array(1, 2, 3)

scala> scala.util.Random.shuffle(a)
res33: Sequence[Int] = Array(2, 1, 3)

scala> scala.util.Random.shuffle(a)
res34: Sequence[Int] = Array(3, 2, 1)

Scala のやり方では、元の配列は変更されないことに注意してください。

于 2009-08-11T14:00:59.067 に答える
5

「ここで正確に何が起こっているのですか?」に答えるために。部:

java.util.Arrays.asList(a) と言うとき、可変数の引数を取るように定義された静的 Java メソッドを呼び出しています (Java の vararg ... 構文):

public static <T> List<T> asList(T... a) 

Scala では、asList を呼び出すときに、3 つの文字列パラメーターではなく、1 つの Array[String] を渡します。Scala は T* を Array[T] として表しますが、3 つのリストである単一のパラメーターではなく、3 つのパラメーターを渡すことを本当に意味していることをコンパイラーに伝える必要があります。

Scala には、Array[String] を String,String,String に変換する便利な方法があります。Walter Chang の回答に示されているように、_* 記号を使用します。vararg 関数に何かを渡すときはいつでも使用できます。

これについては、Programming in Scala の 188 ページと 189 ページで概説されています。

リスト内の 0 個以上の要素に一致するパターン マッチングにも _* が表示されます。

于 2009-08-11T10:34:52.877 に答える