Scala 阿克卡溪流&x2014;按流中的元素数进行过滤
我正在用Scala编写一个应用程序,我正在使用Akka streams 在某一点上,我需要过滤出元素少于N的流,其中N是给定的。因此,例如,对于Scala 阿克卡溪流&x2014;按流中的元素数进行过滤,scala,stream,akka,akka-stream,Scala,Stream,Akka,Akka Stream,我正在用Scala编写一个应用程序,我正在使用Akka streams 在某一点上,我需要过滤出元素少于N的流,其中N是给定的。因此,例如,对于N=5: Source(List(1,2,3)).via(myFilter) // => List() Source(List(1,2,3,4)).via(myFilter) // => List() 将成为空流,并且 Source(List(1,2,3,4,5)).via(myFilter) // => Li
N=5
:
Source(List(1,2,3)).via(myFilter) // => List()
Source(List(1,2,3,4)).via(myFilter) // => List()
将成为空流,并且
Source(List(1,2,3,4,5)).via(myFilter) // => List(1,2,3,4,5)
Source(List(1,2,3,4,5,6)).via(myFilter) // => List(1,2,3,4,5,6)
将保持不变
当然,在结束之前,我们无法知道流中元素的数量,而等到流结束后再推动流通过可能不是最好的主意
因此,我考虑了以下算法:
流元素。是否有一些内置的Akka元素我可以使用
编辑:
好吧,我昨天玩过它,我想出了这样的主意:
Flow[Int].
prefixAndTail(N).
flatMapConcat {
case (prefix, tail) if prefix.length == N =>
Source(prefix).concat(tail)
case _ =>
Source.empty[Int]
}
它会做我想要的吗?这可能是一个小“状态”可以走很长一段路的例子。即使解决方案不是“纯功能性的”,更新状态也会被隔离,系统的其余部分无法访问。我认为这是scala的优点之一:当FP解决方案不明显时,您总是可以以一种孤立的方式恢复到命令式
完成的流程
将是多个子部分的组合。第一个流只是将元素分组为大小为N
的序列:
val group : Int => Flow[Int, Seq[Int], _] =
(N) => Flow[Int] grouped N
现在,对于非功能部件,如果第一个序列的大小正确,则只允许分组的Seq
值通过的过滤器:
val minSizeRequirement : Int => Seq[Int] => Boolean =
(minSize) => {
var isFirst : Boolean = True
var passedMinSize : Boolean = False
(testSeq) => {
if(isFirst) {
isFirst = False
passedMinSize = testSeq.size >= minSize
passedMinSize
}
else
passedMinSize
}
}
}
val minSizeFilter : Int => Flow[Seq[Int], Seq[Int], _] =
(minSize) => Flow[Seq[Int]].filter(minSizeRequirement(minSize))
最后一步是将Seq[Int]
值转换回Int
值:
val flatten = Flow[Seq[Int]].flatMapConcat(l => Source(l))
最后,将它们结合在一起:
val combinedFlow : Int => Flow[Int, Int, _] =
(minSize) =>
group(minSize)
.via(minSizeFilter(minSize))
.via(flatten)
也许statefulMapConcat
可以帮助您:
import akka.actor.ActorSystem
import akka.stream.scaladsl.{Sink, Source}
import akka.stream.{ActorMaterializer, Materializer}
import scala.collection.mutable.ListBuffer
import scala.concurrent.ExecutionContext
object StatefulMapConcatExample extends App {
implicit val system: ActorSystem = ActorSystem()
implicit val materializer: Materializer = ActorMaterializer()
implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global
def filterLessThen(threshold: Int): (Int) => List[Int] = {
var buffering = true
val buffer: ListBuffer[Int] = ListBuffer()
(elem: Int) =>
if (buffering) {
buffer += elem
if (buffer.size < threshold) {
Nil
} else {
buffering = false
buffer.toList
}
} else {
List(elem)
}
}
//Nil
Source(List(1, 2, 3)).statefulMapConcat(() => filterLessThen(5))
.runWith(Sink.seq).map(println)
//Nil
Source(List(1, 2, 3, 4)).statefulMapConcat(() => filterLessThen(5))
.runWith(Sink.seq).map(println)
//Vector(1,2,3,4,5)
Source(List(1, 2, 3, 4, 5)).statefulMapConcat(() => filterLessThen(5))
.runWith(Sink.seq).map(println)
//Vector(1,2,3,4,5,6)
Source(List(1, 2, 3, 4, 5, 6)).statefulMapConcat(() => filterLessThen(5))
.runWith(Sink.seq).map(println)
}
导入akka.actor.ActorSystem
导入akka.stream.scaladsl.{Sink,Source}
导入akka.stream.{Actormatarializer,Materializer}
导入scala.collection.mutable.ListBuffer
导入scala.concurrent.ExecutionContext
对象状态FulMapConcateXample扩展应用程序{
隐式val系统:ActorSystem=ActorSystem()
隐式val-materializer:materializer=ActorMaterializer()
隐式val ec:ExecutionContext=scala.concurrent.ExecutionContext.Implicits.global
def filterLessThen(阈值:Int):(Int)=>列表[Int]={
var缓冲=真
val buffer:ListBuffer[Int]=ListBuffer()
(元素:Int)=>
if(缓冲){
缓冲区+=元素
if(buffer.size<阈值){
无
}否则{
缓冲=假
缓冲区列表
}
}否则{
列表(elem)
}
}
//零
源(列表(1、2、3)).statefulMapConcat(()=>filterLessThen(5))
.runWith(Sink.seq).map(println)
//零
源(列表(1,2,3,4)).statefulMapConcat(()=>filterlessen(5))
.runWith(Sink.seq).map(println)
//向量(1,2,3,4,5)
源(列表(1,2,3,4,5)).statefulMapConcat(()=>filterlessen(5))
.runWith(Sink.seq).map(println)
//向量(1,2,3,4,5,6)
源(列表(1,2,3,4,5,6)).statefulMapConcat(()=>filterlessen(5))
.runWith(Sink.seq).map(println)
}