【问题标题】:Scala groupBy+map issueScala groupBy+map 问题
【发布时间】:2018-11-14 23:19:50
【问题描述】:

此处的示例:Scastie Example

我不明白这是如何工作的。我有一个像这样的元组序列:

val v = Seq(
  ("provider@test.com",2), 
  ("consumer@test.com",2), 
  ("provider@test.com",9), 
  ("provider@test.com",10)
)

我想像这样对它们进行分组:

v.groupBy{ case(email, id) => id }

这会导致:

Map(
  2 -> List(
      (provider@test.com,2),
      (consumer@test.com,2)
  ), 
  10 -> List(
      (provider@test.com,10)
  ), 
  9 -> List(
      (provider@test.com,9)
  )
)

这很有意义,但现在如果我像这样再次映射它们:

v.groupBy{ case(email, id) => id}.map{case(id, data) => data.head}.toSeq

我希望结果是:

Vector((provider@test.com,2), (provider@test.com,10), (provider@test.com,9))

但是我得到:

Vector((provider@test.com,9))

怎么了?

【问题讨论】:

    标签: scala dictionary scala-collections


    【解决方案1】:

    这确实有点令人困惑。发生这种情况是因为 Map[K, V] 上的 map 也返回了 Map[K', V'] 对,并且因为您的密钥都是相同的(邮寄地址),所以您只能返回一个值。

    使用.values 可以避免这种情况,它返回IterableMap 中的值,然后是.map

    v
     .groupBy { case (_, id) => id }
     .values
     .map(_.head)
     .toList
    

    【讨论】:

      【解决方案2】:

      当您不小心在 Map 上调用 map 时,就会发生这种情况。 在这种情况下,对

        2 -> List(
            (provider@test.com,2),
            (consumer@test.com,2)
        ), 
        10 -> List(
            (provider@test.com,10)
        ), 
        9 -> List(
            (provider@test.com,9)
        )
      

      变成对

      (provider@test.com,2)
      (provider@test.com,10)
      (provider@test.com,9)
      

      然后再次插入到新构建的映射中,将值 2 覆盖 10 然后覆盖 9。最终结果是类型为 Map[String, Int] 的映射,带有单个条目 (provider@test.com,9),这当然不是您想要的.

      改为这样做:

      println(v.groupBy{ case(email, id) => id}.toSeq.map{case(id, data) => data.head})
      

      【讨论】:

        【解决方案3】:

        当您执行groupBy 时,您会得到一个Map[Int, Seq[(String, Int)]]map 方法将对Map[Int, Seq[(String, Int)]] 中的每个条目进行操作。如果您只想对可以执行的值进行操作

        v.groupBy{ case(email, id) => id}.mapValues(...
        

        【讨论】:

        • @AndreyTyukin 你是对的。这就是我要写的。我更新了答案
        【解决方案4】:

        这是错误的,因为您在 Map 对象上调用了 map 方法,正如 Andrey Tyukin 已经指出的那样。首先将其转换为列表,然后使用适当的转换函数应用 map 方法,如下所示:
        这有效:

         v.groupBy{ case(email, id) => id}.toList.map(_._2.head)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-10-26
          • 2018-10-23
          • 2011-06-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多