在Scala中进行运算符链接时访问以前的输出

在Scala中进行运算符链接时访问以前的输出,scala,functional-programming,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) 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&g

如何访问结果输出值以执行后续操作,例如:

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)
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)
在上面的一行中,我需要在删除重复项后执行切片操作。为此,我将介绍如何访问
.removeDuplicate()
的输出,以便使用它查找切片操作的
大小

我需要在一个步骤中执行此操作。不是在多个步骤中,例如:

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
的输出,
op2
op3
finalop

中如果使用
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)

如果在一个函数中确实需要它,您可以编写一个自定义的
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
        }
    }
}
var计数=0
val found=new HashSet()
res0.foldLeft(List[Int]()){(z,i)=>
如果(!found.contains(i)){
如果(计数<4){
z:+i
发现+=i
计数+=1
}
}
}

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

包装到
选项中可能是一个选项(没有双关语):

您可以使包裹零件隐式化,使其更美观:

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))

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

假设您的输入是
xs:Seq[String]
,op1的类型是
(xs:Seq[String])=>Seq[String]
。您希望修改op1以返回
案例类ResultWrapper(originalInputLength:Int,deduplicatededitems:Seq[String],somethingNeededInOp5:SomeType)
。如果你所有的行动都将其他行动所需要的东西传递下去,你就会得到你所需要的。这不是很优雅,因为您的操作之间存在耦合:上游需要保存下游需要的信息。在这一点上,它们不再是真正的“不同的操作”


您可以做的一件事是使用Map[a,B]作为“结果包装器”。通过这种方式,ops之间的耦合更少,但类型安全性也更低。

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

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
val res=for{
ls1 val ls=列表(1,1,2,2,3,3,4,4)
ls:List[Int]=List(1,1,2,2,3,3,4,4)
scala>:粘贴
//进入粘贴模式(按ctrl-D键完成)
为了{

ls1 Scala的标准库提供了,因此删除的复制可能是不必要的。例如:
List(1,4,3,4,4,5,6,7)。distinct
=
List[Int]=List(1,4,3,5,6,7)
您想访问所有中间结果吗?或者
op3
的结果足够了吗?我需要所有的结果。请注意,如果您知道只访问op3(即上一个),那么在最后的操作中访问中间结果会很有帮助。
removeDuplicates()
只是一个示例。
list.op1().op2().op3().finalop()
这里我想访问:
finalop
@codestward中的
op1
op2
op3
的输出您在这个评论中要求的与您的问题完全不同。您想在当前方法调用中一般能够访问以前的结果吗?不,
removeDuplicates()
是一个操作(op1,op2,…)的示例。我只是对其进行了概括。您可以通过将op1()中的信息保存到从op1传递到op2的ResultRapper中来实现这一点。因此,不要只传递Result;传递ResultRapper,它包含您需要的中间数据。我使用了
RemovedUpplicates()
仅作为一个示例。基本上,我希望在当前操作中使用所有先前操作的输出。如果您希望在最后一步访问每个步骤的输出,您可能还需要一个
flatTap
;)
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)