我是Scala和typesafeconfig的新手。我有以下问题 - 我有这样的配置 -
a = [
{
b1 = [
{
c1 = 3,
c2 = 4
}, {
c1 = 3,
c2 = 21
}
]
}, {
b2 = [
{
c1 = 10,
c2 = 56
},
# ...many more elements
]
}
# .
# .
# .many more elements
]
我已经能够使用以下代码将上述内容放在Map [String,ConfigValue]中 -
val list : Iterable[ConfigObject] = config.getObjectList(PathTo 'a').asScala
val pairs = for {
item: ConfigObject <- list
entry : Entry[String, Config] <- item.entrySet().asScala
key = entry.getKey
value = entry.getValue.atKey(key)
} yield (key, value)
pairs.toMap
在这个Map中我得到的键是b1,b2等 - 这很好但问题是我得到的值为ConfigValue(我没有找到一个好方法来捕获值List [ConfigObject]或更好的东西)。所以,例如,在运行时我可以看到我对应于键b1的值有两个条目 - {c1 = 3,c2 = 4}和{c1 = 3,c2 = 21}但是我无法遍历这两个条目一个,到达c1和c2。
所以,我对那些在TypeSafeConfig和Scala方面有一些经验的人的问题是 - 是否有更好的方法可以制作我的Map,以便我可以轻松地遍历b1,b2等中的值,或者是否有将我的当前值(即ConfigValue)转换为可迭代的更好的方法。
提前致谢!
答案 0 :(得分:2)
就个人而言,我真的不喜欢Java typesafe配置对象上的接口。这看起来像是一个很好的库,用于向java对象添加更多scala友好的接口:
https://github.com/iheartradio/ficus
要解析您的值,所需的所有代码都是:
val config = ConfigFactory.parseString(
"""
|a = [
| {
| b1 = [
| {
| c1 = 3,
| c2 = 4
| }, {
| c1 = 3,
| c2 = 21
| }
| ]
| }, {
| b2 = [
| {
| c1 = 10,
| c2 = 56
| },
| # ...many more elements
| ]
| }
| # .
| # .
| # .many more elements
| ]
""".stripMargin)
import net.ceedubs.ficus.Ficus._
val myComplicatedStructure = config.as[List[Map[String, List[Map[String, Int]]]]]("a")
println(myComplicatedStructure)
// prints List(Map(b1 -> List(Map(c2 -> 4, c1 -> 3), Map(c2 -> 21, c1 -> 3))), Map(b2 -> List(Map(c2 -> 56, c1 -> 10))))
如果你不想添加另一个库,这将作为java中的一次性解析器工作:
val myComplicatedStructureFromJava = config.getConfigList("a").asScala.toList.map{ relativeConfig =>
relativeConfig.root().entrySet().asScala.map { entry =>
val key = entry.getKey
val configList2 = relativeConfig.getConfigList(key).asScala.toList
key -> configList2.map{ relativeConfig2 =>
relativeConfig2.root().entrySet().asScala.map{ entry2 =>
val key2 = entry2.getKey
key2 -> relativeConfig2.getInt(key2)
}.toMap
}
}.toMap
}
println(myComplicatedStructureFromJava)
// prints List(Map(b1 -> List(Map(c2 -> 4, c1 -> 3), Map(c2 -> 21, c1 -> 3))), Map(b2 -> List(Map(c2 -> 56, c1 -> 10))))
// or, if you just want a List[Map[String, List[Config]]]
val myComplicatedStructureFromJava2: List[Map[String, List[Config]]] = config.getConfigList("a").asScala.toList.map{ relativeConfig =>
relativeConfig.root().entrySet().asScala.map { entry =>
val key = entry.getKey
val configList2 = relativeConfig.getConfigList(key).asScala.toList
key -> configList2
}.toMap
}
println(myComplicatedStructureFromJava2)
// List(Map(b1 -> List(Config(SimpleConfigObject({"c1":3,"c2":4})), Config(SimpleConfigObject({"c1":3,"c2":21})))), Map(b2 -> List(Config(SimpleConfigObject({"c1":10,"c2":56})))))
答案 1 :(得分:1)
方法toMap
位于Collection[(K, V)]
类型的集合(2元组的集合)上,并返回Map[K, V]
。重复的密钥丢失。您需要先按键对每个值进行分组,而不是调用pairs.toMap
:
pairs.groupBy(_._1) // produces a Map[String, Array[(String, ConfigValue)]
.mapValues(_.map(_._1)) // produces a Map[String, Array[ConfigValue]
这使您能够根据需要迭代配置。