继续上一篇关于函数组合的介绍:
谓词组合
还以歌曲过滤器为例说明,前面的歌曲过滤器只能传递一个过滤条件,如果筛选出满足多个条件的歌曲,可以用到“谓词组合”。
object SongDemo3 { type SongFilter = Song => Boolean /** * 给定一个谓词函数predicate,返回和predicate对立的结果. * * @param predicate * @tparam T * @return */ def reverse[T](predicate: T => Boolean) = (a: T) => !predicate(a) def findSingerSongs: Set[String] => SongFilter = singerNames => song => song.singers.exists(singerNames) def removeSingerSongs = findSingerSongs.andThen(reverse(_)) type HotChecker = Int => Boolean def hotFilter: HotChecker => SongFilter = f => song => f(song.hot) def findTopHotSongs: Int => SongFilter = hot => hotFilter(_ >= hot) def findLowHotSongs: Int => SongFilter = hot => hotFilter(_ < hot) /** * 检查是否会有一个谓词输入a为真. * * @param predicates * @tparam T * @return */ def any[T](predicates: (T => Boolean)*): T => Boolean = a => predicates.exists(pred => pred(a)) /** * 是否所有的谓词输入都不为真. * * @param predicates * @tparam T * @return */ def none[T](predicates: (T => Boolean)*) = reverse(any(predicates: _*)) /** * 检查是否每个谓词输入都为真. * * @param predicates * @tparam T * @return */ def every[T](predicates: (T => Boolean)*) = none(predicates.view.map(reverse(_)): _*) def fingSongs(songs: Seq[Song], f: SongFilter) = songs.filter(f) def main(args: Array[String]) { //过滤器,过滤掉歌手名为刘德华的歌曲. val exculdeSingerFilter = removeSingerSongs(Set("刘德华")) val combineFilter: SongFilter = every( removeSingerSongs(Set("刘德华")), findTopHotSongs(100), findLowHotSongs(10000) ) val songs = List( Song(1, "今天", List("刘德华"), 101), Song(2, "笨小孩", List("刘德华"), 20), Song(3, "七里香", List("周杰伦"), 501), Song(4, "吻别", List("张学友"), 20000), Song(5, "浮夸", List("陈奕迅"), 99) ) fingSongs(songs, combineFilter).foreach(println) } }
输出结果:
Song(3,七里香,List(周杰伦),501)