我正在使用Scala 2.9.2,并希望根据某些条件构建一个列表.
考虑以下内容,其中cond是一些函数,它采用谓词p和类型T的值(在本例中为t3):
t1 :: t2 :: cond( p, t3 ) :: t4
Run Code Online (Sandbox Code Playgroud)
我想要的行为如下.如果p为真,则应该给出:
List[T]( t1, t2, t3, t4 )
Run Code Online (Sandbox Code Playgroud)
如果p的计算结果为false,则应该给出:
List[T]( t1, t2, t4 )
Run Code Online (Sandbox Code Playgroud)
我可能完全以错误的方式思考这个问题,但我很难想出一个优雅的解决方案.我可以在任何地方参与选项然后过滤,但这会使代码更难以阅读:
def cond[T]( p : => Boolean, v : T ) : Option[T] =
{
p match
{
case true => Some( v )
case false => None
}
}
Run Code Online (Sandbox Code Playgroud)
这允许以下内容:
scala> ( Some( 1 ) :: Some( 2 ) :: cond( true, 3 ) :: Some( 4 ) :: Nil ).flatten
res4: List[Int] = List(1, 2, 3, 4)
scala> ( Some( 1 ) :: Some( 2 ) :: cond( false, 3 ) :: Some( 4 ) :: Nil ).flatten
res5: List[Int] = List(1, 2, 4)
Run Code Online (Sandbox Code Playgroud)
但是,它不是最优雅的解决方案,因为它要求用户将所有非条件元素包装在Some()中,并且还要记住在最后进行展平.谁能想到更优雅的解决方案?
如何产生一个列表?
@inline def cond[T]( p : => Boolean, v : T ) : List[T] = if(p) v::Nil else Nil
Run Code Online (Sandbox Code Playgroud)
然后使用它们:
List(1,2,3) ++ cond(false, 3 ) ++ List(4)
Run Code Online (Sandbox Code Playgroud)
因此,这无法与标准列表一起使用,因为类型是错误的:::
期望类型的元素[A >: T]
whereT
是列表类型,而您想给它一些可能会或可能不会产生该类型元素的东西.
但是,没有理由不能定义一种方法,它非常乐意接受只能选择性地产生下一个元素的东西。List
本身是密封的,所以我们不能直接扩展它,但是我们可以很容易地复制我们需要的行为:
trait QList[+T] {
def hd : T
def tl : QList[T]
def ?::[A >: T](hd : A) : QList[A] = new ?::[A](hd, this)
def ?::[A >: T](hd : => Option[A]) : QList[A] = hd match {
case Some(a) => ?::(a)
case None => this
}
}
case object QNil extends QList[Nothing] {
def hd = throw new Exception("Head of empty list")
def tl = throw new Exception("Tail of empty list")
}
case class ?::[+T](val hd: T, val tl : QList[T]) extends QList[T]
def cond[T]( p : => Boolean, v : T ) : Option[T] =
{
p match
{
case true => Some( v )
case false => None
}
}
val truelist = 1 ?:: 2 ?:: 3 ?:: cond(true, 4) ?:: 5 ?:: QNil
val falselist = 1 ?:: 2 ?:: 3 ?:: cond(false, 4) ?:: 5 ?:: QNil
Run Code Online (Sandbox Code Playgroud)
我们基本上重新创建了列表,但是用一个带条件的重载前置操作来填充它。
?::
通过使用到具有正确方法的另一个类的隐式转换,可以将方法添加到标准列表中。您提到您使用的是 2.9.2,这是一种耻辱,因为否则这是隐式值类非常适合的那种东西,但我们不需要它们,它们只是让事情变得更容易:
class ConditionallyAppend[T](tl : List[T]) {
def ?::[A >: T](hd : A) : List[A] = hd :: tl
def ?::[A >: T](x : => Option[A]) : List[A] = x match {
case Some(a) => a :: tl
case None => tl
}
}
implicit def ListToConditionallyAppend[A](x : List[A]) = new ConditionallyAppend(x)
Run Code Online (Sandbox Code Playgroud)
现在我们可以这样做:
val truelist = 1 ?:: 2 ?:: 3 ?:: cond(true, 4) ?:: 5 ?:: Nil
truelist: List[Any] = List(1, 2, 3, 4, 5)
和这个:
val falselist = 1 ?:: 2 ?:: 3 ?:: cond(false, 4) ?:: 5 ?:: Nil
falselist: List[Any] = List(1, 2, 3, 5)
归档时间: |
|
查看次数: |
4917 次 |
最近记录: |