【问题标题】:Scala return types with foreach and map带有 foreach 和 map 的 Scala 返回类型
【发布时间】:2016-08-11 05:36:32
【问题描述】:

我是 Scala 新手,我对函数如何拼接在一起以及它们的返回类型感到困惑。考虑以下几点:

val nodes = List(0,1,2)               
val links = List(List(1, 2), List(1, 0), List(1,3))

每个节点都有一个双向链接,如元组对“链接”中所述。我正在尝试构建一个地图,其中每个节点都指向它的邻居,例如

Map(0 -> List(1), 1 -> List(2, 0), 2 -> List(1) )

但是,我最初对如何编写代码的想法让我难以理解为什么它会返回一个空的 'List[Any]' 值。

nodes.foreach(z => (links.map { case List(a,b) => if(a == z) a else if (b == z) b }))

这样做的正确方法是什么?

【问题讨论】:

  • 为什么不1 -> List(0, 2, 3)3不是邻居吗?为什么3 -> List(1) 不在那里?
  • 对的符号是val links = List(1 -> 2, 1 -> 0) 或parens (1,2) 等。
  • 是的,正如@som-snytt 所说,您可能应该使用Tuple2 而不是List 配对,因为我们知道配对总是包含2 个项目。在 Scala 中,要创建 Tuple2,您可以使用 Tuple2(a, b)(a, b)a -> b 中的任何一个。
  • @jwvh,你说得对,应该是 1->List(2,0,3)

标签: scala


【解决方案1】:

或者,

scala> nodes.map(n => (n, links.flatMap {
     | case List(`n`, x) => Some(x)
     | case List(x, `n`) => Some(x)
     | case _ => None }))
res3: List[(Int, List[Int])] = List((0,List(1)), (1,List(2, 0, 3)), (2,List(1)))

如评论,

scala> .toMap
res4: scala.collection.immutable.Map[Int,List[Int]] = Map(0 -> List(1), 1 -> List(2, 0, 3), 2 -> List(1))

【讨论】:

  • 您可能应该在最后调用toMap,因为用户想要获取地图。
  • @Darkhan 是的,我只是想评论另一个答案。
【解决方案2】:

你的代码有一些问题:

首先,foreach 返回Unit,正如您在Scala Doc 中看到的那样

此外,您的情况并不完全正确 - 例如。对于节点0 和连接1<->0,您将打印0,但您实际上想返回1


正确的代码应该是这样的:

val nodes = List(0,1,2)               
val links = List(List(1, 2), List(1, 0), List(1,3))
val result = nodes.map(z => 
    (z, links.flatMap { 
                case List(a,b) => if(a == z && nodes.contains(b)) Some(b) else if (b == z && nodes.contains(a)) Some(a) else None 
              }
    )
).toMap
println(result)

注意我是如何在nodes 列表中调用map(而不是foreach) - 这让我可以在最后调用toMap - 这将返回一个地图(你想要最终实现)。此外,我将每个节点 映射ping 到该节点的Pair 及其邻居列表

注意 2: 我添加了一个条件,用于检查发现的邻居是否是节点集合的一部分(使用 contains) - 因为这就是您的示例。如果您有不同的要求,只需将其删除

将给予:

Map(0 -> List(1), 1 -> List(2, 0), 2 -> List(1))

【讨论】:

  • 我认为结果不应该包含Unit 类型。您可以在if 中使用Option,然后在最后调用flatten
【解决方案3】:

我不确定您的代码示例中的List[Any] 的位置。

但是,foreach 采用返回类型为 Unit 的函数作为参数,因此返回 Unit。对于副作用,它基本上是一个经典的for each loop

List 的“地图”功能集合可以将List[A] 变成List[B]。因此,例如,如果您要在 map 函数中返回 List[Int]Int,则两者的 最小 共同祖先类型将为 Any,因此结果将是 @ 987654333@.

但是,由于 scala 具有非常强大的集合 API,因此有一个简单的解决方案。

明确地,您可以提供一个CanBuildFrom[List[Int], List[Int], Map[Int, Int]] 来从List[Int] 构建一个Map[Int, List[Int]],同时映射 使用函数Int => (Int, Int)

但是 scala 提供了一种更简单的方法来实现这一点(看看breakOut)。

所以,如果我正确地解释了你的问题,你需要这样的东西:

val neighbors: Map[Int, List[Int]] = nodes.map(z =>
  z -> links.withFilter(_.contains(z)).flatMap(_.filter(candidate => candidate != z && nodes.contains(candidate)))
)(collection.breakOut)

--> neighbors: Map[Int,List[Int]] = Map(0 -> List(1), 1 -> List(2, 0), 2 -> List(1))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-26
    • 2019-10-31
    • 1970-01-01
    • 2018-04-29
    • 2016-08-15
    • 2020-07-19
    • 2011-06-06
    相关资源
    最近更新 更多