2009-08-11 57 views
11

Tôi có một mảng mà tôi muốn hoán vị ngẫu nhiên. Trong Java, có một phương thức Collections.shuffle() có thể trộn ngẫu nhiên các phần tử của một List một cách ngẫu nhiên. Nó có thể được sử dụng trên một mảng quá:Làm thế nào để sử dụng Java Collections.shuffle() trên một mảng Scala?

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

tôi đã cố gắng sử dụng này trên một mảng Scala, nhưng người phiên dịch Scala trả lời bằng một câu trả lời dài:

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

gì chính xác đang xảy ra ở đây? Tôi không muốn biên dịch mã của tôi với một lá cờ đặc biệt (-Xno-varargs-conversion), nếu đó là giải pháp ở tất cả, chỉ vì điều này.

Vì vậy, làm cách nào để sử dụng Bộ sưu tập của Java.shuffle() trên một mảng Scala?

tôi đã viết phương pháp ngẫu nhiên của riêng tôi trong Scala trong khi chờ đợi:

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

Nó shuffles mảng tại chỗ, và trả về mảng chính nó cho thuận tiện.

+0

Lưu ý rằng việc xáo trộn theo cách này chỉ hoạt động đối với các loại tham chiếu. – starblue

+0

@ starblue: Có, phiên bản Java chỉ hoạt động đối với các loại tham chiếu. Phương thức Scala shuffle() của riêng tôi cũng làm việc với các mảng Scala với các nguyên thủy. – Jesper

Trả lời

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

Đối với ở trên để làm việc một cách chính xác, một loại nguyên tố có phải là một lớp con của scala.AnyRef (tương đương với java.lang.Object) vì Arrays.asList() sử dụng các mảng thông qua tại như các cửa hàng ủng hộ cho kết quả java.util.List và java.util.List chỉ có thể chứa các tham chiếu đối tượng (không phải các giá trị nguyên thủy). *

Đó cũng là lý do tại sao Collections.shuffle() làm xáo trộn thông tin java.util đã thông qua .List thực sự xáo trộn mảng. *

*: Xem ghi chú bên dưới

Ví dụ:

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) 

Lưu ý: Scala 2.7.5 được sử dụng cho đoạn mã trên. Scala 2.8.0 thể hiện các hành vi khác nhau như Daniel đã chứng minh. Để được ở bên an toàn, không phụ thuộc vào thực tế là mảng bị xáo trộn nhưng thay vào đó danh sách được trả về từ Arrays.asList() bị xáo trộn.

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

Cảm ơn. Nhưng điều đó không làm việc cho một mảng Scala với các số nguyên - nó dẫn đến một ClassCastException, bởi vì mảng không thể được đúc thành một mảng Java của các đối tượng. – Jesper

+0

@Jesper Để Collections.shuffle() hoạt động, hãy đảm bảo mảng chứa tham chiếu đối tượng chứ không phải giá trị nguyên thủy. (scala.Int -> java.lang.Integer, scala.Long -> java.lang.Long, vv) Tôi đã chỉnh sửa câu trả lời để nhấn mạnh điểm này. –

5

Để trả lời "chính xác những gì đang xảy ra ở đây?" một phần:

Khi bạn nói java.util.Arrays.asList (a) bạn đang gọi một phương thức Java tĩnh được định nghĩa để lấy một số biến đối số (cú pháp vararg ... trong Java):

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

Trong Scala khi bạn thực hiện cuộc gọi đến asList, bạn đang chuyển trong một mảng [Chuỗi] và không phải là ba tham số chuỗi. Mặc dù Scala đại diện cho T * là Array [T], bạn cần phải nói cho trình biên dịch biết rằng bạn thực sự muốn truyền ba tham số, chứ không phải là một tham số duy nhất là một Danh sách ba thứ.

Scala có một cách thuận tiện để chuyển đổi mảng [Chuỗi] thành Chuỗi, Chuỗi, Chuỗi: bạn sử dụng biểu tượng _ * như được hiển thị trong câu trả lời của Walter Chang. Bạn có thể sử dụng nó bất cứ khi nào bạn đang chuyển một cái gì đó đến một hàm vararg.

Điều này được nêu trên các trang 188 và 189 của Lập trình ở Scala.

Bạn cũng sẽ thấy _ * trong đối sánh mẫu để khớp với số không hoặc nhiều phần tử trong Danh sách.

6

Có vẻ như Scala đang làm điều gì đó khác với Java khi nói đến các biến thể. Ít nhất, tôi không thể có được mảng đó xáo trộn bất kỳ cách nào tôi cố gắng. Giả sử, shuffle trên danh sách sẽ trộn mảng vì danh sách được hỗ trợ theo mảng. Vâng, có vẻ như Scala sẽ tạo ra một mảng mới khi chuyển đối số vararg sang Java, do đó làm cho ví dụ nói trên vô ích.

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] 

Nó làm việc với Ints, bất chấp tuyên bố khác, mặc dù:

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] 

On Scala 2.8, có một cách đơn giản hơn:

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) 

Lưu ý rằng, trong một thời trang Scala , nó không thay đổi mảng ban đầu.

+0

Daniel, nếu tôi làm điều này: val a = Array ("a", "b", "c") java.util.Collections.shuffle (java.util.Arrays.asList (a: _ *)) thì mảng Scala của tôi không bị xáo trộn. Và nếu tôi tạo một mảng Ints thay vì Strings, tôi sẽ nhận được một ClassCastException. – Jesper

+0

Và cảm ơn cho mẹo về Scala 2.8, do đó sẽ có một phương thức shuffle() trong thư viện trong 2.8. Ofcourse nó trả về một mảng mới, đó là cách chức năng lập trình điển hình. – Jesper

+0

@Daniel Tôi nghĩ bạn đang sử dụng repl 2.8.0. Hãy thử các ví dụ của bạn trong 2.7.5 và bạn sẽ thấy sự khác biệt từ kết quả của mình. Rõ ràng, 2.8.0 tạo ra một Seq mới khi nó thấy ": _ *" nhưng 2.7.5 chỉ bao bọc một Seq xung quanh mảng. –

Các vấn đề liên quan