【问题标题】:Why do I have to explicitly state Tuple2(a, b) to be able to use Map add in a foldLeft?为什么我必须明确声明 Tuple2(a, b) 才能在 foldLeft 中使用 Map add?
【发布时间】:2011-08-21 21:36:40
【问题描述】:

我希望创建一个以名称为键的地图,其中包含具有该名称的事物的数量。我有一个带有名称的事物列表,其中可能包含多个具有相同名称的项目。像这样编码我得到一个错误“类型不匹配;发现:需要字符串:(字符串,整数)”:

//variation 0, produces error 
(Map[String, Int]() /: entries)((r, c) => { r + (c.name, if (r.contains(c.name)) (c.name) + 1 else 1) })

这让我感到困惑,因为我虽然 (a, b) 是一个 Tuple2,因此适合与 Map add 一起使用。以下任一变体均按预期工作:

//variation 1, works
(Map[String, Int]() /: entries)((r, c) => { r + Tuple2(c.name, if (r.contains(c.name)) (c.name) + 1 else 1) })
//variation 2, works
(Map[String, Int]() /: entries)((r, c) => { 
    val e = (c.name, if (r.contains(c.name)) (c.name) + 1 else 1) })
    r + e

我不清楚为什么我的第一个版本有问题;任何人都可以建议。我正在使用 Scala-IDE 2.0.0 beta 2 来编辑源代码;错误来自 Eclipse 问题窗口。

【问题讨论】:

  • entries groupBy (.name) mapValues (.length) // 所以正在吃我的下划线
  • 根据entries 的类型和长度,这可能会执行很多更差。
  • 我认为它总是会变慢。其中,根据您的域,仍然可以被认为是“很多”。

标签: scala tuples scala-collections


【解决方案1】:

将单个元组参数传递给使用运算符表示法的方法时,例如您的 + 方法,您应该使用双括号:

(Map[String, Int]() /: entries)((r, c) => { r + ((c.name, r.get(c.name).map(_ + 1).getOrElse(1) )) })

我还更改了 Int 的计算,这在您的示例中看起来很有趣……

【讨论】:

  • 好的,所以如果我按照它认为r + (a,b) 表示“调用r 上的+ 方法传入a,b,因此r + ((a,b)) 表示“调用r 上的加号方法传入@987654328 @ (例如 Tuple2(a,b)。虽然有点烦人,但确实有道理;谢谢。编辑:感谢 getOrElse 的提醒;从 Java 迁移过来,我仍然倾向于思考?:=> if/else 用于 getOrElse 更有意义的情况。
  • @S42 是的,你明白了。如果你不喜欢双括号,你可以使用Alexey's suggestion 使用“箭头”-> 创建元组。
【解决方案2】:

因为+ 用于将字符串与字符串连接起来。在这种情况下,括号不是表示元组,而是表示参数。

Scala 已经将+ 用于其他东西,这导致了各种问题,就像你提到的那样。

+ 替换为updated,或使用-> 代替,

【讨论】:

    【解决方案3】:
    r + (c.name, if (r.contains(c.name)) (c.name) + 1 else 1)
    

    被解析为

    r.+(c.name, if (r.contains(c.name)) (c.name) + 1 else 1)
    

    所以编译器会在Map 上寻找带有 2 个参数的+ 方法,但没有找到。我更喜欢双括号的形式(正如 Jean-Philippe Pellet 建议的那样)是

    r + (c.name -> if (r.contains(c.name)) (c.name) + 1 else 1)
    

    更新:

    如果Pellet是正确的,最好写

    r + (c.name -> r.getOrElse(c.name, 0) + 1)
    

    (当然,James Iry 的解决方案更好地表达了相同的意图)。

    【讨论】:

    • 但是(c.name) + 1 不是Int... 我认为OP 的意思是r(c.name) + 1。然后,会执行两次查找——一次用于contains,一次用于apply
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-09
    相关资源
    最近更新 更多