根据可选参数值过滤列表

时间:2013-10-22 12:53:02

标签: scala

是否有更优雅的方法根据可选参数值过滤列表?

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个案例等。

6 个答案:

答案 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结合起来以获得一个单行,但我会将其作为练习留给读者。