2009-08-11 11 views
11

मेरे पास एक सरणी है जिसे मैं यादृच्छिक रूप से क्रमबद्ध करना चाहता हूं। जावा में, एक विधि 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> 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) के साथ संकलित नहीं करना चाहता, अगर यह समाधान है, तो बस इसका समाधान है।

तो, मैं स्कैला सरणी पर जावा के संग्रह। शफल() का उपयोग कैसे करूं?

मैं स्काला में अपने ही फेरबदल विधि लिखा था इस बीच में:

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

यह जगह में सरणी shuffles, और सुविधा के लिए सरणी ही देता है। एक के तत्व प्रकार scala.AnyRef (java.lang.Object के बराबर) का एक उपवर्ग हो गया है

+0

ध्यान दें कि इस तरह से फेरबदल केवल संदर्भ के प्रकार के सरणियों के लिए काम करता है। – starblue

+0

@starblue: हां, जावा संस्करण केवल संदर्भ प्रकारों के सरणी के लिए काम करता है। मेरा स्वयं का स्काला शफल() विधि प्राइमेटिव के साथ स्कैला सरणी के साथ भी काम करता है। – Jesper

उत्तर

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

ऊपर के लिए सही ढंग से काम करने के लिए, क्योंकि Arrays.asList() सरणी समर्थन की दुकान के रूप में पारित का उपयोग करता है परिणाम java.util.List और java.util.List में केवल ऑब्जेक्ट संदर्भ (आदिम मान नहीं) हो सकते हैं। *

यही कारण है कि Collections.shuffle() जो पारित java.util को shuffles लिस्ट वास्तव में सरणी को घुमाया। *

*: नीचे दिए गए नोट को देखें

उदाहरण के लिए:

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) 

नोट: स्काला 2.7.5 ऊपर कोड के टुकड़े के लिए प्रयोग किया जाता है। स्केल 2.8.0 डैनियल के प्रदर्शन के रूप में विभिन्न व्यवहार प्रदर्शित करता है। सुरक्षित पक्ष पर रहने के लिए, इस तथ्य पर निर्भर न करें कि सरणी shuffled हो जाता है, लेकिन इसके बजाय Arrays.asList() से वापस की गई सूची shuffled हो जाता है।

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

धन्यवाद। लेकिन यह पूर्णांक वाले स्कैला सरणी के लिए काम नहीं करता है - इसका परिणाम क्लासकास्ट अपवाद में होता है, क्योंकि सरणी को ऑब्जेक्ट्स की जावा सरणी में नहीं डाला जा सकता है। – Jesper

+0

@ जेस्पर संग्रह के लिए .shuffle() काम करने के लिए, सुनिश्चित करें कि सरणी में ऑब्जेक्ट संदर्भ हैं और आदिम मान नहीं हैं। (Scala.Int -> java.lang.Integer, scala.Long -> java.lang.Long, आदि) मैं इस सवाल का जवाब इस बात पर जोर देना संपादित किया है। –

5

"वास्तव में क्या हो रहा है?" का उत्तर देने के लिए भाग:

जब आप कहते हैं कि java.util.Arrays.asList (क) आप एक स्थिर जावा विधि है जो तर्क के परिवर्तनशील (vararg ... जावा में सिंटेक्स) लेने के लिए परिभाषित किया गया है कॉल कर रहे हैं:

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

स्काला में जब आप कॉल asList करने के लिए आप नहीं तीन स्ट्रिंग पैरामीटर एक एकल सरणी [स्ट्रिंग] में गुजर और कर रहे हैं। हालांकि स्कैला टी * को एरे के रूप में दर्शाता है [टी] आपको संकलक को बताने की ज़रूरत है कि आप वास्तव में तीन पैरामीटर को पार करने के लिए तीन पैरामीटर गुजरने का मतलब है, जो तीन चीजों की सूची है।

स्कैला के पास आपके ऐरे [स्ट्रिंग] को स्ट्रिंग, स्ट्रिंग, स्ट्रिंग में परिवर्तित करने का एक सुविधाजनक तरीका है: आप वाल्टर चांग के उत्तर में दिखाए गए _ * प्रतीक का उपयोग करते हैं। जब भी आप एक vararg फ़ंक्शन में कुछ पास कर रहे हों तो आप इसका उपयोग कर सकते हैं।

यह स्कैला में प्रोग्रामिंग के पेज 188 और 18 9 पर उल्लिखित है।

आप सूची में शून्य या अधिक तत्वों से मेल खाने के लिए पैटर्न मिलान में _ * भी देखेंगे।

6

यह स्काला जावा से कुछ अलग कर रही है जब यह varargs की बात आती है लगता है। कम से कम, मैं उस सरणी को किसी भी तरह से शफल नहीं कर सकता। माना जाता है कि सूची में शफल सरणी को घुमाएगा क्योंकि सूची सरणी समर्थित है। ठीक है, ऐसा लगता है कि स्काला जब जावा के लिए vararg तर्क गुजर, इसलिए ऊपर उल्लिखित उदाहरण बेकार बना एक नई सरणी पैदा करेगा।

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 साथ काम करता है, दावा के बावजूद करता है, हालांकि:

स्काला 2.8 पर
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> 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) 

ध्यान दें कि, एक स्काला फैशन में , यह मूल सरणी नहीं बदलता है।

+0

डैनियल, मैं यह कर यदि: वैल एक = सरणी ("एक", "बी", "सी") java.util.Collections.shuffle (java.util.Arrays.asList (क: _ *)) फिर मेरे स्काला सरणी फेरबदल हो जाता है। और यदि मैं स्ट्रिंग्स के बजाय इंट्स की एक सरणी बना देता हूं, तो मुझे क्लासकास्ट अपवाद मिलता है। – Jesper

+0

और स्काला 2.8 के बारे में टिप के लिए धन्यवाद, तो 2.8 में पुस्तकालय में एक फेरबदल() विधि नहीं होगा। यह एक नई सरणी देता है, यह प्रोग्रामिंग का ठेठ कार्यात्मक तरीका है। – Jesper

+0

@ डैनियल मुझे लगता है कि आप 2.8.0 प्रतिलिपि का उपयोग कर रहे हैं। 2.7.5 में अपने उदाहरणों का प्रयास करें और आप अपने परिणामों से मतभेद देखेंगे। जाहिर है, 2.8.0 एक नया सीक उत्पन्न करता है जब यह ": _ *" देखता है लेकिन 2.7.5 सरणी के चारों ओर एक सेक लपेटता है। –