是否有更优雅的方法根据可选参数值过滤列表?
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 :(得分:9)
一种方法如下:
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 < _) )
答案 1 :(得分:5)
对于任意数量的过滤器:
您可以先将参数更改为List [Option [Date =&gt;布尔]。然后组合实际存在的所有过滤器。然后应用组合过滤器。
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))
答案 2 :(得分: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)
}
答案 3 :(得分:0)
我同意同事们说,最好在每种情况下都有单独的过滤器。为此,最好使用.filter
方法。不过,您还需要将Data
转换为Long
。这可以通过隐式转换器来完成:
implicit def dateToLong(d:Date) = d.getTime
然后你只是做过滤:
dates.view.filter(_ >= start).filter(_ <= finish)
如果您仍然需要可选过滤器,则隐式“pimp-my-library”可以提供帮助
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)
}
答案 4 :(得分:0)
val l1 = startDate.map { d => dates.filter(_ > d) }
val l2 = endDate.map { d => dates.filter(_ < d) }
l1.getOrElse(dates).intersect(l2.getOrElse(dates))
答案 5 :(得分: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)
}
你几乎可以肯定地将一些Min / Max Monoid概括为你的开始和结束args,并将它与Ordering结合起来以获得一个单行,但我会将其作为练习留给读者。