我想对序列进行排序和/或过滤。基本上是这样的:
var result = getReallyLongSeq() // returns Seq[SomeClass]
if (doFilter) {
result = result.filter( ... )
}
if (doSort) {
result = result.sortWith( ... )
}
现在,这显然是一种有效的方法,但有没有更实用的方法呢?
我想对序列进行排序和/或过滤。基本上是这样的:
var result = getReallyLongSeq() // returns Seq[SomeClass]
if (doFilter) {
result = result.filter( ... )
}
if (doSort) {
result = result.sortWith( ... )
}
现在,这显然是一种有效的方法,但有没有更实用的方法呢?
它是否更具可读性还有待商榷。它的效率有点低,但它也纯粹是功能性的。这种方法也很容易扩展并且相当可维护。
val f: Seq[SomeClass] => Seq[SomeClass] = if(doFilter) _.filter(...) else identity
val s: Seq[SomeClass] => Seq[SomeClass] = if(doSort) _.sortWith(...) else identity
(s compose f)(result)
您也可以编写以下内容,这更像是OP中的代码。它也稍微更有效(但不太通用)。
val filtered = if(doFilter) result.filter(...) else result
if(doSort) filtered.sortWith(...) else filtered
如果由于某些原因您更喜欢在第一个示例中使用 curried 函数(如评论中所述),您可以编写以下内容:
def fc(df: Boolean)(xs: Seq[SomeClass]) = if(df) _.filter(...) else identity
def sc(ds: Boolean)(xs: Seq[SomeClass]) = if(ds) _.sortWith(...) else identity
(sc(doSort) compose fc(doFilter))(result)
但是你可能会像这样进一步编写它,并最终得到与第一个示例中给出的几乎相同的内容:
def fc(df: Boolean)(xs: Seq[SomeClass]) = if(df) _.filter(...) else identity
def sc(ds: Boolean)(xs: Seq[SomeClass]) = if(ds) _.sortWith(...) else identity
val f = fc(doFilter)
val s = sc(doSort)
(s compose f)(result)
您可以使用scalaz oparator|>
或定义自己的:
class PipedObject[T](value: T)
{
def |>[R](f: T => R) = f(value)
}
implicit def toPiped[T](value: T) = new PipedObject[T](value)
(result |> (r => if (doFilter) r.filter(...) else r)
|> (r => if (doSort) r.sortWith(...) else r))
如果没有库支持,您可以推出自己的Boolean Reader Monad。
这是功能性的、纯粹的和可配置的。
布尔阅读器
case class BoolConf[A](run: Boolean => A) {
def apply(b: Boolean) = run(b)
def map[B](f: A => B): BoolConf[B] = BoolConf(b => f(run(b)))
def flatMap[B](f: A => BoolConf[B]): BoolConf[B] = BoolConf(b => f(run(b))(b))
}
Boolean => A
在这里,我们为 a 制作了一个允许单子组合的包装器,它可能已经在某些库中实现,例如scalaz。
对于这种情况,我们只对run
方法感兴趣,但您可以对其他机会感兴趣。
配置过滤和排序
然后我们用Reader
val mFilter: Seq[SomeClass] => BoolConf[Seq[SomeClass]] = seq => BoolConf(if(_) seq.filter(...) else seq)
val mSort: Seq[SomeClass] => BoolConf[Seq[SomeClass]] = seq => BoolConf(if(_) seq.sortWith(...) else seq)
起重
现在,要组合这些函数,由于输出不再是简单的Seq
,我们需要提升其中一个以在 aBoolConf
def lift2Bool[A, B]: (A => B) => (BoolConf[A] => BoolConf[B]) =
fun => cfg => BoolConf(bool => fun(cfg(bool)))
现在我们可以将任何函数 from 转换A => B
为提升函数 fromBoolConf[A] => BoolConf[B]
构成
现在我们可以函数式地组合:
val filterAndSort = lift2Bool(mSort) compose mFilter
//or the equivalent
val filterAndSort = mFilter andThen lift2Bool(mSort)
//applies as in filterAndSort(<sequence>)(<do filter>)(<do sort>)
还有更多
我们还可以为我们的mFilter
和创建一个通用的“构建器”mSort
val configFilter[SomeClass]: (SomeClass => Boolean) => Seq[MyClass] => BoolConf[Seq[SomeClass]] =
filterer => seq => BoolConf(if(_) seq.filter(filterer))
您可以自己“排序”排序等价物
感谢 Runar 的启发