如何使用同一流中存在的键对流的元素进行分组?

时间:2019-06-12 18:03:30

标签: scala akka akka-stream

所以我有以下类型:

case class Episode(
  parentTconst: String,
  seasonNumber: Int,
  episodeNumber: Int
)

以及以下来源:

val episodeSource: Source[Episode, _] = FileIO.fromPath(Paths.get(myDataFilePath)).via(myDataParserToEpisode)

情节清单示例如下:

Seq(
  Episode("gameof", 5, 8),
  Episode("mentalist", 2, 4),
  Episode("gameof", 5, 8),
  Episode("mentalist", 1, 8),
  Episode("rikiandmanual", 1, 8)
)

我正在尝试创建以下流程(不确定我是否是正确的签名,请告知,也许这是一个接收器,因为我正在消耗整个流来获取地图)

def gimmeThoseEpisodeGroups: Flow[Episode, Map[String, Seq[Episode]], _]

如果打印出来,看起来会像这样:

Map(
  "gameof"        -> Seq(Episode("gameof", 5, 8), Episode("gameof", 5, 8)),
  "mentalist"     -> Seq(Episode("mentalist", 2, 4), Episode("mentalist", 1, 8)),
  "rikiandmanual" -> Seq(Episode("rikiandmanual", 1, 8))
)

我尝试了很多无效的组合。也许方法不正确。

我认为我应该使用groupBy。 另一件事是,也许我需要第一次使用流来获取组的键列表(或者找到一种方法来使用它一次但产生两个结果)。

我DuckDucked并发现了有关广播的信息,但是我还没有全神贯注。

    def getGroupedByParentTConst: Flow[Episode, Map[String, Seq[Episode]], _] = Flow[Episode].groupBy(2, _.parentTconst)

但这失败了(无论如何,我觉得这不是正确的路径。

此外,我想我会提取parentTconst来使用它们作为分组键:

    def getParentTConst: Flow[Episode, Set[String], _] = Flow[Episode].fold(Set.empty[String]) {
      (right, left) => { right ++ Set(left.parentTconst) }
    }

那行得通,但是我一直在努力弄清楚如何使用它们对我的原始资源进行分组...

此外,如果我使用键列表,那意味着我将必须消耗两个流才能进行分组。

我认为我有一个Duck问题,这不是一个真正困难的问题,但是由于我有使用akka流的约束,所以这并不是很简单。

任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

您要实现的目标不能以流方式完成,因为创建所有分组情节的地图需要读取内存中的所有数据。没有任何中间结果。

如果您仍然希望这样做,可以按照与提议的方式类似的方式使用折叠

Flow[Episode].fold(Map.empty[String, List[Episode]]) { (map, e) ⇒
  val key = e.parentTconst
  map + (key → v :: map.getOrElse(key, Nil))
}

但是由于那将读取内存中的所有文件,因此您还可以节省使用akka流的麻烦,而只需使用scala.io.Source

如果您有太多数据无法容纳在内存中,则需要更改要求。