2012-02-04 8 views
24

के एक सरल मानचित्रण उदाहरण पर विचार करें:स्कैला में एक सरणी मैप करते समय तत्व अनुक्रमणिका कैसे प्राप्त करें?


    val a = Array("One", "Two", "Three") 
    val b = a.map(s => myFn(s)) 

क्या मैं जरूरत नहीं myFn(s: String): String यहाँ है, लेकिन myFn(s: String, n: Int): String, जहां na में s के सूचकांक होगा उपयोग करने के लिए है। इस विशेष मामले में myFn दूसरे तर्क को एस == "वन" के लिए 0 होने की उम्मीद करेगा, एस == "दो" के लिए 1 और एस == "तीन" के लिए 2। इसे कैसे प्राप्त किया जा सकता है?

उत्तर

66

निर्भर करता है कि आप सुविधा या गति चाहते हैं या नहीं।

धीरे

:

a.zipWithIndex.map{ case (s,i) => myFn(s,i) } 

तेज़:

संभवत: सबसे तेजी से:

Array.tabulate(a.length){ i => myFn(a(i),i) } 

यदि नहीं, तो इस निश्चित रूप से है:

val b = new Array[Whatever](a.length) 
var i = 0 
while (i < a.length) { 
    b(i) = myFn(a(i),i) 
    i += 1 
} 

(जावा 1.6u37 के साथ स्कैला 2.10.1 में, यदि "संभवतः सबसे तेज़" को एक छोटे स्ट्रिंग ऑपरेशन (कुछ वर्णों के लिए लंबी स्ट्रिंग का छंटनी) के लिए 1x समय लेने के लिए घोषित किया जाता है, तो "धीमी" 2x लंबी होती है, "तेजी" प्रत्येक 1.3x अधिक समय लग सकता है, और "निश्चित रूप से" केवल समय 0.5x लेता है)

+17

मैं गति सामान पर अपने जवाब पढ़ने प्यार कर रहा हूँ, लेकिन यह कभी कभी तो निराशाजनक हो सकता है ... :-) –

+0

धन्यवाद। एक चयन बहुत अच्छा है। – Ivan

+0

'a.view.zipWithIndex.map {केस (एस, i) => myFn (s, i)} की गति कैसे आपके समाधानों की तुलना करता है? – gzm0

4

एक सामान्य टिप:। उपयोग .iterator विधि उदारतापूर्वक, मध्यवर्ती संग्रह के निर्माण से बचने, और इस तरह अपने गणना तेजी लाने के लिए। (केवल प्रदर्शन की आवश्यकताओं को यह मांग करते हैं। वरना ऐसा नहीं।)

scala> def myFun(s: String, i: Int) = s + i 
myFun: (s: String, i: Int)java.lang.String 

scala> Array("nami", "zoro", "usopp") 
res17: Array[java.lang.String] = Array(nami, zoro, usopp) 

scala> res17.iterator.zipWithIndex 
res19: java.lang.Object with Iterator[(java.lang.String, Int)]{def idx: Int; def idx_=(x$1: Int): Unit} = non-empty iterator 

scala> res19 map { case (k, v) => myFun(k, v) } 
res22: Iterator[java.lang.String] = non-empty iterator 

scala> res22.toArray 
res23: Array[java.lang.String] = Array(nami0, zoro1, usopp2) 

ध्यान रखें कि iterators परिवर्तनशील होते हैं, और इसलिए एक बार सेवन किया फिर से उपयोग नहीं किया जा सकता।


एक तरफ एक: map कॉल ऊपर de-tupling और फिर समारोह प्रयोग शामिल है। यह बल कुछ स्थानीय चर का उपयोग करते हैं। आप कुछ उच्च आदेश जादूगर का उपयोग करके इससे बच सकते हैं - एक नियमित फ़ंक्शन को एक स्वीकार्य टुपल में परिवर्तित करें, और उसके बाद इसे map पर पास करें।

scala> Array("nami", "zoro", "usopp").zipWithIndex.map(Function.tupled(myFun)) 
res24: Array[java.lang.String] = Array(nami0, zoro1, usopp2) 
+0

"इटरेटर म्यूटेबल हैं, और इसलिए उपभोग करने के बाद फिर से उपयोग नहीं किया जा सकता है" - मैंने एक बार कुछ समय डिबगिंग बिताई है क्यों प्रोग्राम एक बार उपयोग करने के लिए एक इटरेटर को खाली करने के लिए काम नहीं करता है :-) – Ivan

3

इसके बारे में क्या? मुझे लगता है कि यह तेज़ होना चाहिए और यह सुंदर है। लेकिन मैं स्काला गति पर कोई विशेषज्ञ ...

a.foldLeft(0) ((i, x) => {myFn(x, i); i + 1;})