2013-10-22 4 views
6

क्या वैकल्पिक पैरामीटर मानों के आधार पर सूची फ़िल्टर करने का एक और शानदार तरीका है?वैकल्पिक पैरामीटर मानों के आधार पर एक सूची फ़िल्टर करना

def f(dates: List[Date], start: Option[Long], end: Option[Long]): List[Date] = { 
    (start, end) match { 
     case (Some(s), Some(e)) => dates filter (_.getTime > s) filter (_.getTime < e) 
     case (Some(s), None) => dates filter (_.getTime > s) 
     case (None, Some(e)) => dates filter (_.getTime < e) 
     case (None, None) => dates 
    } 
} 
तीन वैकल्पिक पैरामीटर मान के साथ

इस 9 मामलों आदि के लिए होता है

+0

बस एक sidenote: यदि आप एक श्रृंखला में एक मोनैडिक निर्माण (एक सूची की तरह) में एकाधिक फ़िल्टर का उपयोग करना चाहते हैं, तो उस सूची में एक दृश्य का उपयोग करें। तिथियां .view.filter (...)। तिथियों के बजाय फ़िल्टर (...)। फ़िल्टर (...)। फ़िल्टर (...) – Guillaume

उत्तर

8

एक ही रास्ता के रूप में किया जाएगा इस प्रकार है:

def f(dates: List[Date], start: Option[Long], end: Option[Long]): List[Date] = 
    dates.filter(d => start.map(d.getTime > _).getOrElse(true)) 
     .filter(d => end.map(d.getTime < _).getOrElse(true)) 

या, और भी अधिक संक्षिप्त, आप विकल्पों पर forall इस्तेमाल कर सकते हैं :

def f(dates: List[Date], start: Option[Long], end: Option[Long]): List[Date] = 
    dates.filter(d => start.forall(d.getTime > _)) 
     .filter(d => end.forall(d.getTime < _)) 
5

फ़िल्टर की मनमानी मात्रा के मामले में:

आप पहले सूची [विकल्प [दिनांक => बूलियन]] में पैरामीटर बदल सकते हैं। फिर वास्तव में वहां मौजूद सभी फ़िल्टरों को गठबंधन करें। फिर संयुक्त फ़िल्टर लागू करें।

def f(dates : List[Date], filters : List[Option[Date => Boolean]]) = { 
    val combFilter = filters.foldLeft((d : Date) => true)((comb, filter) => if(filter.isDefined) (d : Date) => comb(d) && filter.get(d) else comb) 
    dates.filter(combFilter) 
} 

और तुम यह सोचते है की तारीख, आरंभ और समाप्ति, आप इसे पसंद कॉल कर सकते हैं:

f(dates, List(start.map(s => _.getTime > s), end.map(e => _.getTime < e)) 
+0

फ़ोल्ड लेफ्ट दृष्टिकोण – Guillaume

0

मैं सहयोगियों के साथ सहमत हैं कि यह हर शर्त पर अलग फिल्टर करने के लिए बेहतर है। इस उद्देश्य के लिए .filter विधि का उपयोग करना अच्छा है। हालांकि आपको Data को Long में कनवर्ट करने की भी आवश्यकता है। यह एक अंतर्निहित कनवर्टर के साथ किया जा सकता है:

implicit def dateToLong(d:Date) = d.getTime 

तो फिर तुम बस छानने कार्य करें:

dates.view.filter(_ >= start).filter(_ <= finish) 

आप अभी भी वैकल्पिक फिल्टर की जरूरत है तो एक अंतर्निहित "दलाल-मेरी-पुस्तकालय" में मदद कर सकते

implicit class ListWithOptionalFilters[T](datas:List[T]){ 
    def filterOpt(f:Option[T=>Boolean]) = 
    datas.filter(d => f.forall(d)) 

} 

तो आप यह कर इस प्रकार है:

def f(dates: List[Date], start: Option[Long], end: Option[Long]) = { 
    val startFilter = start.map(l => (d:Date) => d>=l) 
    val endFilter = end.map(l => (d:Date) => d<=l) 
    dates.filterOpt(startFilter).filterOpt(endFilter) 
} 
0
val l1 = startDate.map { d => dates.filter(_ > d) } 
val l2 = endDate.map { d => dates.filter(_ < d) } 
l1.getOrElse(dates).intersect(l2.getOrElse(dates)) 
+0

के लिए +1 यदि एल 1/एल 2 'कोई नहीं 'है, 'तारीखें 'वापस नहीं की जानी चाहिए, न कि' शून्य '। (क्योंकि आप कुछ भी फ़िल्टर नहीं करते हैं)। और आप केवल उन तत्वों को रखना चाहते हैं जिनमें दोनों सूचियां शामिल हों, न कि संगतता।(चूंकि तत्वों को दोनों स्थितियों को पूरा करना चाहिए) – Kigyo

+0

आप सही हैं, मैंने अभी अपना जवाब सही किया –

1

मुझे लगता है कि आपके प्रश्न में कुंजी एक सार्थक स्थिति में प्रदान किए गए पैरामीटर को कैसे परिवर्तित करना है। फिर आप उस विधि को किसी भी पैरामीटर (फ़िल्टरिंग स्थितियों) तक बढ़ा सकते हैं।

एक आंतरिक रूपांतरण का उपयोग करना (हां, तो आपके कोड क्या पैरामीटर के साथ क्या करना जानता है), मैं इस तरह के दृष्टिकोण होगा:

def f(dates: List[Date], start: Option[Long], end: Option[Long]): List[Date] = { 
     val filters = List(start.map(x=>{y:Long=>y>x}), end.map(x=>{y:Long=>y<x})).flatten 
     dates.flatMap(date => if (filters.forall(filter => filter(date.getTime))) Some(date) else None) 
    } 
0

इस विशेष मामले के लिए, मैं का उपयोग करेंगे:

def f(dates: List[Date], oStart: Option[Long], oEnd: Option[Long]): List[Date] = { 
    val start = oStart.getOrElse(Long.MinValue) 
    val end = oEnd.getOrElse(Long.MaxValue) 
    dates.filter(date => date.getTime > start && date.getTime < end) 
} 

आप अपने प्रारंभ और अंत तर्क के लिए लगभग कुछ न्यूनतम/अधिकतम मोनोइड को सामान्य रूप से सामान्यीकृत कर सकते हैं, और एक लाइनर प्राप्त करने के लिए इसे ऑर्डरिंग के साथ संयोजित कर सकते हैं, लेकिन मैं इसे पाठक के लिए एक अभ्यास के रूप में छोड़ दूंगा।

संबंधित मुद्दे