我有这样的逻辑:数据文件需要经历一系列操作,但是否需要操作是由一些布尔值控制的。基本上,数据数组经过过程循环并产生一些结果。
我想知道是否有一种优雅的方式对此进行编码,希望不使用var
和许多if
/ else
语句?
def op1(data): Seq[int]
def op2(data): Seq[int]
def op3(data): Seq[int]
def process(data: Seq[int], b1: boolean, b2: boolean, b3: boolean) = {
//NOT working code, some thing does the following:
var temp: Seq[int] = data
if (b1)
temp = op1(temp)
if(b2)
temp = op2(temp)
if(b3)
temp = op3(temp)
temp
}
答案 0 :(得分:1)
在这种情况下,我实际上更喜欢你的解决方案,但这是一个更实用的选择。我用字符串替换了Seq,因为它们更容易用于示例,但这无关紧要。
object SequenceOfOperations {
def op1(data: String) = data + "A" //> op1: (data: String)java.lang.String
def op2(data: String) = data + "B" //> op2: (data: String)java.lang.String
def op3(data: String) = data + "C" //> op3: (data: String)java.lang.String
def process(data: String, b1: Boolean, b2: Boolean, b3: Boolean) = {
val ops =Seq((b1 , op1(_)),(b2 , op2(_)),(b3 , op3(_)))
val filteredOps = ops.filter( _._1).map (_._2)
filteredOps.foldLeft(data)((l : String,o : String => String) => o(l))
} //> process: (data: String, b1: Boolean, b2: Boolean, b3: Boolean)String
process("Z", true, false, true) //> res0: String = ZAC
process("Y", true, true, false) //> res1: String = YAB
process("X", false, false, true) //> res2: String = XC
}
答案 1 :(得分:0)
这看起来像一个典型的折叠,您可以将其包装在以下函数中:
def maybeDo[A](bs: List[Boolean], fs: List[A => A], x: A) =
(bs zip fs).foldLeft(x) {
case (x, (b, f)) => if (b) f(x) else x
}
使用它,例如如下
> val bs = List(true, false, true)
> val fs: List[Int => Int] = List(_+1, _*3, _+2)
> maybeDo(bs, fs, 10)
res0: Int = 13
在您的示例中,它将类似于
val temp = maybeFold(List(b1, b2, b3), List(op1 _, op2 _, op3 _), data)
答案 2 :(得分:0)
有很多方法可以实现这一目标。
一种可能的方式是......
def op1(data: Seq[Int]) = data.map(_ + 2) //your actual operation here..
def op2(data: Seq[Int]) = data.map(_ - 2) //..returning Seq[Int]
def op3(data: Seq[Int]) = data.map(_ * 2) //
implicit class SeqOps(val data: Seq[Int]) extends AnyVal {
def op(op: Seq[Int] => Seq[Int], b: Boolean) = if (b) op(data) else data
}
然后def process
可写成..
def process(data: Seq[Int], b1: Boolean, b2: Boolean, b3: Boolean) = {
data op (op1, b1) op (op2, b2) op (op3, b3)
}
答案 3 :(得分:0)
假设您希望流程签名不会改变......
// continuing from the ops psuedocode
def process(data: Seq[Int], b1:Boolean, b2:Boolean, b3:Boolean): Seq[Int] = {
@tailrec
def loop (acc: Seq[Int], ops: List[Seq[Int] => Seq[Int]]): Seq[Int] = {
ops match {
case List () => acc
case head :: tail => loop (head(acc), tail)
}
}
loop (data, List(( b1,op1 _), (b2,op2 _),(b3,op3 _)).filter{ _._1 }.map{ _._2 })
}
解决方案是将op与正确的布尔配对,在List中,过滤掉具有不真实布尔值的对,将过滤后的对映射到操作列表(基本上删除每个幸存对的布尔部分),然后累积您的输入数据递归转换。
以下是一些简单运算符的结果: import scala.annotations.tailrec
def op1(s: Seq[Int]) = s map {_ + 1}
def op2(s: Seq[Int]) = s map {_ * 2}
def op3(s: Seq[Int]) = s map {_ - 5}
def process(data: Seq[Int], b1:Boolean, b2:Boolean, b3:Boolean): Seq[Int] = {
@tailrec
def loop (acc: Seq[Int], ops: List[Seq[Int] => Seq[Int]]): Seq[Int] = {
ops match {
case List () => acc
case head :: tail => loop (head(acc), tail)
}
}
loop (data, List(( b1,op1 _), (b2,op2 _),(b3,op3 _)).filter{ _._1 }.map{ _._2 })
}
process(Seq(1,2,3), true, false, true) // Seq[Int] = List(-3, -2, -1)
process(Seq(1,2,3), true, false, false) // Seq[Int] = List(2, 3, 4)
process(Seq(1,2,3), false, true, false) // Seq[Int] = List(2, 4, 6)