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
如果我有一个如下所示的列表:
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