【问题标题】:Scala: groupBy based on boolean applied to next elementScala:groupBy基于应用于下一个元素的布尔值
【发布时间】:2015-12-31 19:27:38
【问题描述】:

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

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:”,因此将其添加为一个值。

【问题讨论】:

    标签: scala scala-collections scalaz


    【解决方案1】:

    假设你列表的结构是

    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)
    

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

    【讨论】:

      【解决方案2】:

      使用 multiSpan 中定义的 https://stackoverflow.com/a/21803339/3189923 ,给定

      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
      

      【讨论】:

        【解决方案3】:

        再次假设结构总是如上所述:

        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

        【讨论】:

        • 对不起,我漏掉了key是用冒号“注释”的,并且项目数量未知,所以我的解决方案不起作用。
        • 如果总是有 3 个尾随项,这肯定会起作用!
        猜你喜欢
        • 1970-01-01
        • 2021-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-21
        • 2013-08-13
        相关资源
        最近更新 更多