Как преобразовать ConfigValue в List[ConfigObject] в typesafeconfig

Я новичок в 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

На этой карте я получаю ключи как b1, b2 и т. д. - это нормально, но проблема в том, что я получаю значения как ConfigValue (и я не нашел хорошего способа захвата значений List[ConfigObject] или что-то лучше). Так, например, во время выполнения я вижу, что значение, соответствующее ключу b1, имеет две записи — {c1=3, c2=4} и {c1=3, c2=21}, но я не могу пройти по этим двум по одному и добраться до c1 и c2.

Итак, мой вопрос к людям с небольшим опытом работы с TypeSafeConfig и Scala: есть ли лучший способ сделать свою карту, чтобы я мог легко перемещаться по значениям в b1, b2 и т. д., или есть хороший способ преобразовать мое текущее значение, которое является ConfigValue, во что-то лучшее, что можно повторять.

Заранее спасибо!


person Kumar Vaibhav    schedule 10.12.2016    source источник


Ответы (2)


Метод toMap находится в коллекции типа Collection[(K, V)] (наборы из двух кортежей) и возвращает Map[K, V]. Дубликаты ключей потеряны. Вместо вызова pairs.toMap вам нужно сначала сгруппировать каждое значение по его ключу:

pairs.groupBy(_._1)         // produces a Map[String, Array[(String, ConfigValue)]
  .mapValues(_.map(_._1))   // produces a Map[String, Array[ConfigValue] 

Это должно дать вам возможность перебирать конфигурации по мере необходимости.

person Tim    schedule 10.12.2016

Лично мне очень не нравятся интерфейсы в объектах конфигурации Java с безопасным типом. Это похоже на хорошую библиотеку для добавления более удобных для Scala интерфейсов к объектам Java:

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})))))
person lyjackal    schedule 10.12.2016
comment
Я понимаю вашу точку зрения, но я бы не хотел включать библиотеку в кодовую базу, в которой я новичок :) - person Kumar Vaibhav; 10.12.2016
comment
Понятно. Просто пытаюсь понять глупый java API. Посмотрим, смогу ли я написать что-нибудь полезное. Это последний тип, который вам нужен List[Map[String, List[Map[String, Int]]]]? - person lyjackal; 10.12.2016