эквивалент ассоциации (clojure) в Scala - PullRequest
0 голосов
/ 29 ноября 2018

Я пытаюсь найти эквивалент ассоциации (clojure) в Scala.Я пытаюсь конвертировать

(defn- organiseDataByTradeId [data]
(reduce #(let [a (assoc-in %1 
                        [(%2 "internaltradeid") (read-string (%2 "paramseqnum")) "levelcols"] 
                        (reduce (fn [m k](assoc m k (get %2 k))) 
                                {} 
                                (string/split xmlLevelAttributesStr #",")))
            b (assoc-in a



                      [(%2 "internaltradeid") (read-string (%2 "paramseqnum")) "subLevelCols" (read-string (%2 "cashflowseqnum"))]
                         (reduce (fn [m k] (assoc m k (get %2 k))) 
                                {} 
                                (string/split xmlSubLevelAttributesStr #","))               
                        )] 
            b)
      {}
      data))

в scala.Пробовал это:

def organiseDataByTradeId(data: List[Map[String, String]]) = {
    data.map { entry => Map(entry("internaltradeid") -> Map(entry("paramseqnum").toInt -> Map("levelcols" -> (xmlLevelAttributesStr.split(",")).map{key=> (key,entry(key))}.toMap,
        "subLevelCols" -> Map(entry("cashflowseqnum").asInstanceOf[String].toInt -> (xmlSubLevelAttributesStr.split(",")).map{key=> (key,entry(key))}.toMap)))) }

  }

Не уверен, как объединить список карт, которые я получил без перезаписи.Здесь data List [Map [String, String]] в основном описывает таблицу. Каждая запись является строкой. Имена столбцов являются ключами карт, а значения являются значениями. xmlLevelAttributeStr и xmlSubLevelAttributeStr - это две строки, в которых имена столбцов разделены запятой.Я довольно новичок в скале.Я преобразовал каждую строку (Map [String, String]) в карту Scala и теперь не уверен, как их объединить, чтобы предыдущие данные не перезаписывались и вели себя точно так же, как и код clojure. Также мне не разрешается использовать внешние библиотеки, такие какscalaz.

1 Ответ

0 голосов
/ 29 ноября 2018

Этот код Clojure не является хорошим шаблоном для копирования: в нем много дублирования и мало объяснений того, что он делает.Я бы написал так:

(defn- organiseDataByTradeId [data]
  (let [level-reader (fn [attr-list]
                       (let [levels (string/split attr-list #",")]
                         (fn [item]
                           (into {} (for [level levels]
                                      [level (get item level)])))))
        attr-levels (level-reader xmlLevelAttributesStr)
        sub-levels (level-reader xmlSubLevelAttributesStr)]
    (reduce (fn [acc item]
              (update-in acc [(item "internaltradeid"),
                              (read-string (item "paramseqnum"))]
                         (fn [trade]
                           (-> trade
                               (assoc "levelcols" (attr-levels item))
                               (assoc-in ["subLevelCols", (read-string (item "cashflowseqnum"))]
                                         (sub-levels item))))))
            {}, data)))

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

Еще проще, если вы знаете, что не будет дублирования internaltradeid: вы можете просто сгенерировать несколько независимых карт и объединить их вместе:

(defn- organiseDataByTradeId [data]
  (let [level-reader (fn [attr-list]
                       (let [levels (string/split attr-list #",")]
                         (fn [item]
                           (into {} (for [level levels]
                                      [level (get item level)])))))
        attr-levels (level-reader xmlLevelAttributesStr)
        sub-levels (level-reader xmlSubLevelAttributesStr)]
    (apply merge (for [item data]
                   {(item "internaltradeid")
                    {(read-string (item "paramseqnum"))
                     {"levelcols" (attr-levels item),
                      "subLevelCols" {(read-string (item "cashflowseqnum")) (sub-levels item)}}}}))))

Нона самом деле, ни один из этих подходов не будет работать в Scala, потому что у Scala иная философия моделирования данных, чем у Clojure.Clojure поощряет использование свободно определенных гетерогенных карт, таких как эта, где Scala предпочитает, чтобы ваши карты были однородными.Когда у вас будут данные, смешивающие несколько типов, Scala предлагает вам определить класс (или, возможно, класс кейсов - я не эксперт по Scala), а затем создать экземпляры этого класса.

Итак, здесь вы бы хотели Map[String, Map[Int, TradeInfo]], где TradeInfo - это класс с двумя полями, levelcols : List[Attribute] и subLevelCols в качестве некоторой пары (или, возможно, одноэлементной карты)содержащий cashflowseqnum и еще один List[Attribute].

После того, как вы смоделировали свои данные способом Scala, вы будете весьма далеки от использования всего, что выглядит как assoc-in, потому что ваши данные выиграли 'это не одна гигантская карта, поэтому вопрос не возникнет.

...