2011-11-22 12 views
16

कहते हैं कि हम minBy कि एक संग्रह में बराबर अतिसूक्ष्मवाद के सभी तत्वों को रिटर्न की तरह एक समारोह बनाना चाहते में मूल संग्रह प्रकार रिटर्निंग हमारे शुरुआती List के बजाय।सामान्य विधि

तो मैं आशा में

def multiMinBy[A, B: Ordering, C <: Traversable[A]](xs: C)(f: A => B) 

के हस्ताक्षर को बदलने मैं एक C मिल सकता है वापस बल्कि एक Traversable[A] से कोशिश की। हालांकि, मैं कुछ भी वापस नहीं मिलता है:

scala> multiMinBy(List("zza","zzza","zzb","zzzb"))(_.last) 

<console>:9: error: inferred type arguments [Nothing,Nothing,List[java.lang.String]] 
do not conform to method multiMinBy's type parameter bounds [A,B,C <: Traversable[A]] 

मुझे लगता है कि इस वजह से हम C बहस में प्रदर्शित होने से पहले A inferred किया गया है? तो मैं बहस के क्रम फ़्लिप, और एक डाली कहा:

def multiMinBy[A, B: Ordering, C <: Traversable[A]](f: A => B)(xs: C) = { 
    val minVal = f(xs minBy f) 
    (xs filter (f(_) == minVal)).asInstanceOf[C] 
} 

जो, काम करता है को छोड़कर हम इसे इस तरह कॉल करनी होगी:

multiMinBy((x: String) => x.last)(List("zza","zzza","zzb","zzzb")) 

वहाँ एक रास्ता मूल वाक्य रचना बनाए रखने के लिए है, सही संग्रह प्रकार वापस प्राप्त करते समय?

उत्तर

20

मुझे लगता है कि माइल्स सबिन समाधान बहुत जटिल है। स्काला का संग्रह पहले से ही एक बहुत छोटे से बदलाव के साथ, यह काम करने के लिए आवश्यक मशीनरी है:

import scala.collection.TraversableLike 
def multiMinBy[A, B: Ordering, C <: Traversable[A]] 
       (xs: C with TraversableLike[A, C]) 
       (f: A => B): C = { 
    val minVal = f(xs minBy f) 
    xs filter (f(_) == minVal) 
} 
+3

हां, मैं मानता हूं, यह मेरा से बेहतर समाधान है। –

10

आपका समस्या यह है कि filter विधि का परिणाम प्रकार GenTraversable[A] से अधिक नहीं सटीक है जब GenTraversable[A] पर एक विधि (जो मैं इस सवाल का जवाब में Traversable[A] का उपयोग करेंगे) के रूप में देखा है। दुर्भाग्य से multiMinBy विधि के शरीर के भीतर लिखा गया है कि आप xs के बारे में जानते हैं।

परिणाम प्राप्त करने के बाद आपको multiMinBy का हस्ताक्षर अधिक सटीक बनाना होगा। इस जबकि कर अभी भी कंटेनर प्रकार अपेक्षाकृत खुला छोड़ करने का एक तरीका है, इस प्रकार एक संरचनात्मक प्रकार का उपयोग करने के लिए है

type HomFilter[CC[X] <: GenTraversable[X], A] = 
    CC[A] { def filter(p : A => Boolean) : CC[A] } 

def multiMinBy[CC[X] <: GenTraversable[X], A, B: Ordering] 
    (xs: HomFilter[CC, A])(f: A => B) : CC[A] = { 
    val minVal = f(xs minBy f) 
    xs filter (f(_) == minVal) 
    } 

संरचनात्मक प्रकार HomFilter बात पर जोर देना है कि multiMinBy को तर्क वांछित के साथ एक filter विधि होनी चाहिए की अनुमति देता है परिणाम प्रकार।

नमूना आरईपीएल सत्र,

scala> val mmb = multiMinBy(List("zza","zzza","zzb","zzzb"))(_.last) 
mmb: List[String] = List(zza, zzza) 

याद रखिए कि इस से कि कंटेनर बस हो Traversable एक सख्त आवश्यकता है में: यह GenTraversable के उपप्रकार filter तरीकों जो इस तरह से नियमित रूप से नहीं कर रहे हैं परिभाषित करने के लिए के लिए अनुमति है । उपर्युक्त हस्ताक्षर स्थिर रूप से multiMinBy पर पारित होने से मूल्यों को रोक देगा ... संभवतः यह वह व्यवहार है जिसके बाद आप हैं।

+0

एक से बच सकते हैं पूरे संरचनात्मक टाइपिंग सिर्फ TraversableLike' का उपयोग कर 'द्वारा thingy। –

13

CanBuildFrom का उपयोग करने के बारे में कैसे?

import scala.collection.immutable._ 
import scala.collection.generic._ 

def multiMinBy[A, B, From[X] <: Traversable[X], To](xs: From[A])(f: A => B) 
    (implicit ord: Ordering[B], bf: CanBuildFrom[From[_], A, To]) = { 
    val minVal = f(xs minBy f) 
    val b = bf() 
    b ++= (xs filter (f(_) == minVal)) 
    b.result 
} 



scala> multiMinBy(List("zza","zzza","zzb","zzzb"))(_.last) 
res1: List[java.lang.String] = List(zza, zzza) 
संबंधित मुद्दे