【问题标题】:Scala for yield loop not providing expected outputScala for yield 循环未提供预期输出
【发布时间】:2024-04-26 19:25:02
【问题描述】:

以下示例代码sn -p:

val deck = for {
  suit <- Suit.values
  rank <- Rank.values
} yield {
  println(s"$rank $suit")
  PlayingCard(suit, rank)
}
print(deck)

提供以下输出:

王牌炉灶
两个壁炉
三个壁炉
四个壁炉
五炉
六个壁炉
七炉
八炉
九炉
十个壁炉
杰克壁炉
王后壁炉
王炉
王牌钻石
两颗钻石
三颗钻石
四颗钻石
五颗钻石
六颗钻石
七颗钻石
八颗钻石
九颗钻石
十颗钻石
杰克钻石
女王钻石
国王钻石
黑桃王牌
两个黑桃
三黑桃
四个黑桃
五个黑桃
六黑桃
七黑桃
八黑桃
九黑桃
十个黑桃
杰克黑桃
黑桃皇后
黑桃王
王牌俱乐部
两个俱乐部
三个俱乐部
四个俱乐部
五个俱乐部
六个俱乐部
七个俱乐部
八家具乐部
九个俱乐部
十个俱乐部
杰克俱乐部
皇后俱乐部
国王俱乐部

TreeSet(梅花 A、梅花二、梅花三、梅花四、梅花五、梅花六、梅花七、梅花八、梅花九、梅花十、梅花杰克、王后俱乐部之王,俱乐部之王)

我完全不知道为什么这段代码正确地遍历所有卡片,但似乎只返回最后一个花色(是梅花)

【问题讨论】:

    标签: scala collections equals for-comprehension


    【解决方案1】:

    可能是因为您正在构建 TreeSet,但您为 PlayingCard 实现了相等性错误,因此它正在丢弃您想要保留的元素。如果PlayingCard.equals 只考虑牌的等级,而忽略花色,就会发生这种情况。

    如果实现了PlayingCard.equals,它忽略了花色,那么每当您将任何花色的A 添加到Set 时,它都会删除之前的A。这似乎是您看到的问题。

    要解决这个问题,要么更改PlayingCard.equals 的定义以考虑西装,要么强制使用不关心相等性的不同集合类型,例如Vector:

    val deck = for {
      suit <- Suit.values.toVector
      rank <- Rank.values.toVector
    } yield {
      println(s"$rank $suit")
      PlayingCard(suit, rank)
    }
    print(deck)
    

    【讨论】:

    • 哇,这么有限的信息很好。我确实将 PlayingCard 实现为 Ordered 仅考虑等级而不是花色。不过,我也必须将西装转换为矢量才能使该解决方案起作用。是否有任何其他方法可以明确定义将返回的集合类型,因为这可能会导致意外结果。
    • 当您使用 for-comprehension 时,您最终将在您正在迭代的基础集合上使用 mapflatMap。看看这些方法的签名,你会发现它们有两个类型参数——一个是目标元素类型,另一个是要构建的新集合类型。目标集合默认为同一类型,但您可以自行设置。如果您显式调用 mapflatMap 而不是使用 for-comprehension,那么您可以控制目标集合类型。