scala map收集相当于groovy map collect

时间:2016-07-07 05:11:39

标签: scala groovy

我想要嵌套地图中特定键的所有值列表。我在groovy中有一个非常漂亮的例子,如下所示。

class HashTableExperiment {

    static def retailPackages = [
            "package1": [
                    "items"       : ["white shirt", "blue pants", "blue shirt"],
                    "shippingDate": new Date(2016, 10, 28)
            ],
            "package2": [
                    "items"       : ["blue shirt", "brown pants", "blue converse"],
                    "shippingDate": new Date(2016, 11, 23)
            ]
    ]

    static def itemInventory() {
        retailPackages.entrySet().collect {it.value.items}.flatten()
    }

    static def main(String[] args) {
        itemInventory().each {
            println(it)
        }
    }
}

输出

white shirt
blue pants
blue shirt
blue shirt
brown pants
blue converse

我想在scala中实现这个实现,不能像groovy那样自然地做到。

object MapExperiment {

  val retailPackages = Map(
    "package1" -> Map(
      "items" -> List("white shirt", "blue pants", ""),
      "shippingDate" -> new Date(2016, 10, 28)
    ),
    "package2" -> Map(
      "items" -> List("blue shirt", "brown pants", "blue converse"),
      "shippingDate" -> new Date(2016, 11, 23)
    )
  )

  def itemInventory(): Unit = {
    val items = retailPackages.map(p => p._2).map(it => it("items"))
    items.flatten
  }
}

我在flatten中得到以下编译错误

Error:(25, 11) No implicit view available from java.io.Serializable => scala.collection.GenTraversableOnce[B].
    items.flatten
          ^

另外,我的假设是items变量的类型应为List[List[String]],nope,scala编译器应该是Iterable[Serializable]。至少,Iterable[Iterable[String]]是有意义的,但Serializable来自哪里?

当我给它一个类型时,

val items : Iterable[Serializable] = retailPackages.map(p => p._2).map(it => it("items"))

它说Iterable[Serializable] doesn't conform to Iterable[Serializable]

2 个答案:

答案 0 :(得分:1)

您可以强制从SerializableList[String]

的项目
@ MapExperiment.retailPackages("package1")("items")
res11: Object with java.io.Serializable = List(white shirt, blue pants, )

@ MapExperiment.retailPackages("package1")("items").asInstanceOf[List[String]]
res12: List[String] = List("white shirt", "blue pants", "")

然后flatten有效:

@ MapExperiment.retailPackages map { _._2 } map { _("items").asInstanceOf[List[String]] } flatten
res13: collection.immutable.Iterable[String] = List("white shirt", "blue pants", "", "blue shirt", "brown pants", "blue converse")

或在单个地图中:

@ MapExperiment.retailPackages map { _._2("items").asInstanceOf[List[String]] } flatten
res14: collection.immutable.Iterable[String] = List("white shirt", "blue pants", "", "blue shirt", "brown pants", "blue converse")

答案 1 :(得分:0)

这是因为 retailPackages 是混合类型:

Map(
  String -> Map (
    String -> List,
    String -> Date
  )
)

因此,当映射“项目”时,它无法推断类型,您可以使用case来匹配类型:

retailPackages.map(i => i._2("items")).flatMap{case l: List[String] => l}

建议是:使用案例类作为元素,例如:

case class MyObject(items: List[String], shippingDate: Date)
val retailPackages = Map(
    "package1" -> MyObject(List("white shirt", "blue pants", ""), new Date(2016, 10, 28))
      ,
    "package2" -> MyObject(List("blue shirt", "brown pants", "blue converse"),new Date(2016, 11, 23))
)
retailPackages.flatMap(i => i._2.items)