Scala:基于应用于下一个元素的布尔值的groupBy

Scala: groupBy based on boolean applied to next element

如果我有一个如下所示的列表:

List("abdera.apache.org lists:", "commits", "dev", "user",
"accumulo.apache.org lists:", "commits", "dev", "notifications", "user")

我想以

结尾
Map("abdera.apache.org lists:" -> Seq("commits", "dev", "user"), 
"accumulo.apache.org lists:" -> Seq("commits", "dev", "notifications", "user"))

我该怎么做?

我一直在尝试 groupBy,但我不确定如何应用布尔值来首先获取密钥(即 string.contains("lists:")),然后将布尔值应用于下一个要测试的元素如果它不包含 "lists:",因此将其添加为一个值。

假设你列表的结构是

List(key, item, item, item, 
     key, item ..., item, 
     key, item, ...)

您可以使用 foldLeft:

构建这样的地图
val list = List("abdera.apache.org lists:", "commits", "dev", "user",
  "accumulo.apache.org lists:", "commits", "dev", "notifications", "user")

val map: Map[String, List[String]] =
  list.foldLeft(List.empty[(String, List[String])]) {

    case (acc, curr) if curr.endsWith("lists:") =>
      // identified a list key
      curr -> List.empty[String] :: acc

    case (((headListKey, headList)) :: tail, curr) =>
      // append current string to list of strings of head, until next list key is found
      (headListKey, curr :: headList) :: tail

  }.toMap.mapValues(_.reverse)

如果键字符串并不总是以相同方式结束,您可能需要使用正则表达式来识别列表中的键字符串。

再次假设结构始终如上所示:

val list = List("abdera.apache.org lists:", "commits", "dev", "user",
  "accumulo.apache.org lists:", "commits", "dev", "notifications", "user")

Map(list.grouped(4).map(l => (l.head -> l.tail)).toList : _*)

如果您坚持要获得 Seq,那么您可以改为 l.tail.toSeq

使用 中定义的 multiSpan,给定

val xs = List("abdera.apache.org lists:", "commits", "dev", "user",
              "accumulo.apache.org lists:", "commits", "dev",
                                            "notifications", "user")

我们有

xs.multiSpan(_.contains("lists:"))

提供列表列表,

List(List(abdera.apache.org lists:, commits, dev, user),
     List(accumulo.apache.org lists:, commits, dev, notifications, user))

因此,我们可以将生成的嵌套列表转换为所需的 Map,例如,

xs.multiSpan(_.contains("lists:")).map( ys => ys.head -> ys.tail ).toMap