【问题标题】:Loop and create list in Scala在 Scala 中循环并创建列表
【发布时间】:2016-12-23 04:25:36
【问题描述】:

当我尝试使用 :: 运算符创建列表时,我得到了空列表。我的代码如下所示:

def getAllInfo(locks: List[String]): List[LockBundle] = DB.withTransaction { implicit s =>
  val myList = List[LockBundle]()
  locks.foreach(
    l => findForLock(l) :: myList
  )
  myList
} 

def findForLock(lock: String): Option[LockBundle] = { ... }

有什么建议吗?

【问题讨论】:

    标签: scala


    【解决方案1】:

    使用flatMap

    locks.flatMap(l => findForLock(l))
    

    你的代码变成了

    def getAllInfo(locks: List[String]): List[LockBundle] = DB.withTransaction { implicit s =>
      locks.flatMap(l => findForLock(l))
    } 
    

    您也可以使用mapflatten。像这样locks.map(l => findForLock(l)).flatten

    函数式编程是关于转换的。您只需使用您的函数findForLock 的转换将现有列表转换为另一个列表。

    您的代码有问题

    val myList = List[LockBundle]()
      locks.foreach(
        l => findForLock(l) :: myList
      )
      myList
    

    首先foreach 返回Unit 因此,您使用 foreach 进行副作用操作而不是转换。因为你需要转换所以不要使用foreach

    接下来,findForLock(l) :: myList 会为您提供一个值,但这会被忽略,因为没有人存储生成的值。因此,为了存储值,请使用累加器并将其作为函数参数传递,以防递归。

    更正您的代码

    如果您想按照自己的方式行事。您需要使用累加器。

    首先修复你的类型findForLock(l)返回Option,你的列表是List[LockBundle]类型,所以将列表类型更改为List[Option[LockBundle]]

    为了从List[Option[LockBundle]] 获得List[LockBundle],只需在List[Option[LockBundle]] 列表中执行flatten。见下面代码sn-p

      var myList = List[Option[LockBundle]]()
      locks.foreach(
        l => myList = findForLock(l) :: myList
      )
      myList.flatten
    

    以上方式无效,不推荐使用。

    【讨论】:

      【解决方案2】:

      您的代码不起作用,因为 foreach 组合器为每个元素调用给定的闭包,但您在这里所做的只是返回表达式 findForLock(l) :: myList 被丢弃。

      正如pamu 建议的那样,您可以在函数上使用flatMap 将每个元素映射到findForLock 返回的值并展平该列表,如果OptionSome,则将其转换为列表的元素,如果不是这是None

      请记住,这只是因为存在从OptionSeq 的隐式转换,通常flatMap 仅在您返回与给定monad 相同的类型时才有效(在这种情况下为ListOption)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-06-19
        • 2020-07-13
        • 2019-08-12
        • 2011-12-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多