【问题标题】:How to properly map a tuple function across a Seq[A]?如何在 Seq[A] 上正确映射元组函数?
【发布时间】:2013-07-28 16:27:53
【问题描述】:

我有一个函数试图构建一个 JSON 对象,该对象包含存储在 Seq[A] 中的多个元组的表示,其中 A(Loop, Option[User])。我的代码如下所示:

def loops = Action {
    val page : Int = 1
    val orderBy : Int = 1
    val filter : String = ""
    val jsonifyLoops : (Loop, Option[User]) => Map[String, String] = { 
      case (loop,user) =>
            Map(
                "name" -> loop.name,
                "created_at" -> loop.createdAt.map(dateFormat.format).getOrElse(""),
                "deleted_at" -> loop.deletedAt.map(dateFormat.format).getOrElse(""),
                "user_name" -> user.map(_.name).getOrElse("")
            )
    }
    Ok(toJson(Map(
        "loops" -> toJson(
            Loop.list( page = page, orderBy = orderBy, filter = ("%"+filter+"%") )
                .items.map( jsonifyLoops )
            )
        )
    ))
}

Loops.list 产生一个Page[A],来自下面的帮助类:

case class Page[A](items: Seq[A], page: Int, offset: Long, total: Long) {
    lazy val prev = Option(page - 1).filter(_ >= 0)
    lazy val next = Option(page + 1).filter(_ => (offset + items.size) < total)
}

因此,Loops.list(...).items 应该给我一个Seq[(Loop, Option[User])],我应该能够在其上应用地图功能。我已经定义了我的 jsonifyLoops 函数来拥有我认为合适的原型,但我一定是做错了什么,因为编译器会抛出以下错误:

    [error] [...] Application.scala:42: type mismatch;
    [error]  found   : (models.Loop, Option[models.User]) => Map[String,String]
    [error]  required: (models.Loop, Option[models.User]) => ?
    [error]                     .items.map( jsonifyLoops )
    [error]                                 ^

我做错了什么?

【问题讨论】:

    标签: scala map tuples sequence


    【解决方案1】:

    您的函数jsonifyLoops 有两个参数:LoopOption[User]。然而,items 的成员是(Loop, Option[User]) 类型的元组,因此items.map 需要一个接受该元组的参数的函数作为参数。因此,您需要将jsonifyLoops 从二元函数转换为接受一对参数的一元函数; Function2#tupled 会为你做这件事:

    scala> :t jsonifyLoops
    (Loop, Option[User]) => Map[String,String]
    scala> :t jsonifyLoops.tupled
    ((Loop, Option[User])) => Map[String,String]
    

    你会这样使用它:

    Loop.list(page = page, orderBy = orderBy, filter = ("%"+filter+"%"))
        .items.map(jsonifyLoops.tupled)
    

    【讨论】:

    • 啊。这就说得通了。谢谢你的回答。接受。
    【解决方案2】:

    您需要在 jasonifyLoops 中为您的模式匹配添加一个默认大小写。 在没有默认案例的情况下,如果您的案例陈述失败,您将返回一个单元。 所以这样的事情应该可以工作:

    val jsonifyLoops : (Loop, Option[User]) => Map[String, String] = { 
      case (loop,user) =>
            Map(
                "name" -> loop.name,
                "created_at" -> loop.createdAt.map(dateFormat.format).getOrElse(""),
                "deleted_at" -> loop.deletedAt.map(dateFormat.format).getOrElse(""),
                "user_name" -> user.map(_.name).getOrElse("")
            )
      case _ => Map[String, String]()
    }
    

    这只是说如果输入不匹配,则返回一个空 Map。但是,您应该将其替换为您想要对默认情况执行的任何处理。

    【讨论】:

    • 注意默认大小写可以写成case _ =&gt; Map.empty
    • 不幸的是,这似乎并没有解决问题。我从编译器得到同样的错误。还有其他想法吗?
    • 您能否也将 toJson 的定义添加到您的问题中。我想这应该是造成问题的原因。
    • toJson 在 Play 的 Json 库中定义:playframework.com/documentation/2.0/ScalaJson
    猜你喜欢
    • 1970-01-01
    • 2018-10-17
    • 1970-01-01
    • 2014-03-04
    • 1970-01-01
    • 1970-01-01
    • 2021-02-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多