在Scala中进行操作员链接时访问以前的输出

时间:2016-11-17 15:13:07

标签: scala functional-programming

如何访问结果输出值以执行即将进行的操作,例如:

scala> List(1,4,3,4,4,5,6,7)
res0: List[Int] = List(1, 4, 3, 4, 4, 5, 6, 7)

scala> res0.removeDuplicates.slice(0, ???.size -2)

在上面一行中,我需要在删除重复项后执行切片操作。为此,如何访问.removeDuplicate()的输出,以便我可以使用它来查找切片操作的size

我需要一步完成。不是像以下几个步骤:

scala> res0.removeDuplicates
res1: List[Int] = List(1, 4, 3, 5, 6, 7)

scala> res1.slice(0, res1.size -2)
res2: List[Int] = List(1, 4, 3, 5)

我想在最后的操作中访问中间结果。 removeDuplicates()只是一个例子。

list.op1().op2().op3().finalop()我想在op1

中访问:op2op3finalop的输出

5 个答案:

答案 0 :(得分:4)

进入Option可能是一种选择(没有双关语):

val finalResult = Some(foo).map { foo => 
  foo.op1(foo.stuff)
}.map { foo => 
  foo.op2(foo.stuff)
}.map { foo => 
  foo.op3(foo.stuff)
}.get.finalOp

您可以隐藏包装部分以使其更好一些:

object Tapper {
  implicit class Tapped[T] extends AnyVal(val v: T) {
     def tap[R](f: T => R) = f(v)
  }
}

import Tapper._
val finalResult = foo
 .tap(f => f.op1(f.stuff))
 .tap(f => f.op2(f.stuff))
 .tap(f => f.finalOp(f.stuff))

答案 1 :(得分:4)

使用进行理解,可以以非常易读的方式编写操作,并且能够访问中间结果:

val res = for {
  ls1 <- Option(list.op1)
  ls2 = ls1.op2()           // Possible to access list, ls1
  ls3 = ls2.op3()           // Possible to access list, ls1, ls2
} yield ls4.finalOp()       // Possible to access list, ls1, ls2, ls3

例如:

scala> val ls = List(1,1,2,2,3,3,4,4)
ls: List[Int] = List(1, 1, 2, 2, 3, 3, 4, 4)

scala> :paste
// Entering paste mode (ctrl-D to finish)

for {
  ls1 <- Option(ls.map(_ * 2))
  ls2 = ls1.map(_ + ls1.size)
  ls3 = ls2.filter(_ < ls1.size + ls2.size)
} yield ls3.sum

// Exiting paste mode, now interpreting.

res15: Option[Int] = Some(72)

答案 2 :(得分:1)

如果您使用dropRight

,则无需知道长度
scala> val a = List(1,4,3,4,4,5,6,7)
a: List[Int] = List(1, 4, 3, 4, 4, 5, 6, 7)

scala> a.dropRight(2)
res0: List[Int] = List(1, 4, 3, 4, 4, 5)

这样做:res0.removeDuplicates.dropRight(2)

答案 3 :(得分:1)

如果你真的需要一个函数,你可以编写一个自定义foldLeft,如下所示:

var count = 0
val found = new HashSet()
res0.foldLeft(List[Int]()) { (z, i) =>
    if(!found.contains(i)){
        if(count < 4){
            z :+ i
            found += i
            count += 1
        }
    }
}

然而,我并没有真正看到像res0.removeDuplicates.slice这样的链接中的问题。函数式编程的一个好处是我们的编译器可以在这样的情况下进行优化,我们只想要某种行为并且不想指定实现。

答案 4 :(得分:1)

您希望通过一系列转换处理一些数据:someData - &gt; op1 - &gt; op2 - &gt; op3 - &gt; finalOp。但是,在op3中,您希望能够访问op1中完成的处理的中间结果。这里的关键是将下游所需的所有信息传递给处理链中的下一个函数。

假设您的输入为xs: Seq[String],而op1的类型为(xs: Seq[String]) => Seq[String]。您想要修改op1以返回case class ResultWrapper(originalInputLength: Int, deduplicatedItems: Seq[String], somethingNeededInOp5: SomeType)。如果您的所有操作都传递了其他操作需要的操作,您将获得所需的操作。它不是很优雅,因为你的操作之间存在耦合:上游需要保存下游需要的信息。此时它们不再是“不同的操作”。

您可以做的一件事是使用Map [A​​,B]作为“结果包装器”。这样,操作之间的耦合就会减少,但类型安全性也会降低。