如何为同一个源组合`count`和`sum`计算

时间:2017-06-14 11:36:50

标签: scala akka-stream

有一些整数流:

val source = Source(List(1,2,3,4,5))

是否有可能从源获得(count, sum)结果?对于上面的示例,它将是(5, 15)

我想我应该使用流量并将它们组合起来:

val countFlow = Flow[Int].fold(0)((c, _) => c + 1)
val sumFlow = Flow[Int].fold(0)((s, e) => s + e)

如何将上述流量应用于源。或者还有另一种方式吗?

4 个答案:

答案 0 :(得分:1)

最终合计

您提供的Flow对于在消息来源耗尽后获取最终值几乎是正确的:

case class Data(sum : Int = 0, count : Int = 0)

val updateData : (Data, Int) => Data = 
  (data, i) => Data(data.sum + i, data.count + 1)

val zeroData = Data()

val countAndSum = Flow[Int].fold(zeroData)(updateData)

然后可以将此Flow与Sink.head组合以获得最终结果:

val result : Future[Data] = 
  source
    .via(countAndSum)
    .runWith(Sink[Data].head)

中级值

如果你想要一个“跑步计数器”,例如如果您想要所有中间数据值,则可以使用Flow.scan代替fold:

val intermediateCountAndSum = 
  Flow[Int].scan(zeroData)(updateData)

您可以将这些Data值“排放”到Sink.seq

val intermediateResult : Future[Seq[Data]] = 
  source
    .via(intermediateCountAndSum)
    .runWith(Sink[Data].seq)

答案 1 :(得分:1)

val graph = Source.fromGraph(GraphDSL.create() { implicit builder =>
    import GraphDSL.Implicits._

    val fanOut = builder.add(Broadcast[Int](2))
    val merge = builder.add(Zip[Int, Int])

    source ~> fanOut ~> countFlow ~> merge.in0
              fanOut ~> sumFlow ~> merge.in1

    SourceShape(merge.out)
  })


  graph.runWith(Sink.last)

答案 2 :(得分:0)

您可以简单地执行以下操作

source.map(list => (list.length, list.reduceLeft(_+_)))

我希望它有用

答案 3 :(得分:0)

case class Stats(sum: Int, count: Int) {
  def add(el: Int): Stats = this.copy(sum = sum += el, count = count +=1)
}

object Stats {
  def empty: Stats = Stats(0, 0)
}

val countFlow = Flow[Status].fold(Stats.empty)((stats, e) => stats add e)