Как объединить два списка карт в Clojure - PullRequest
0 голосов
/ 12 февраля 2020

У меня есть данные в формате ниже.

'(({:nums {:test number?, :data (1)}})
  {:Other ()} 
  ({:nums {:test number?, :data (2)}})
  ({:nums {:test number?, :data (3 4)}}))

Но я хотел бы получить данные в формате ниже.

'(({:nums {:test number?, :data (1 2 3 4)}}) 
  {:Other ()})

Пробовал с объединением, объединением функций, но не работал. Не могли бы вы помочь здесь, поскольку я новичок в закрытии.

Выполнение тестов по приведенному ниже коду

(split '(1 2 (3 4 [1 2 3])) {:nums {:test number?}})
=> 
((({:nums {:test number?, :data (1)}}) {:Other ()})
  (({:nums {:test number?, :data (2)}}) {:Other ()})
  (({:nums {:test number?, :data (3 4)}}) {:Other (([1 2 3]))}))

Но целевой результат, которого я ожидаю, как показано ниже

(split '(1 2 (3 4 [1 2 3])) {:nums {:test number?}})
=> 
(({:nums {:test number?, :data (1 2 3 4)}}) 
 {:Other ([1 2 3])})

Используемый код:

(defn test
  [list1 filter1]
  ;(get-in (first (first (split list1 filter1))) [:nums :test])
  (first (first (split list1 filter1))))

(defn split [list1 filter_map]
  (if (empty? list1)
    ()
    (cons (split_list
            (if (sequential? (first list1))
              (first list1)
              (list (first list1)))
            filter_map)
      (split (rest list1) filter_map))))

(defn split_list [list1 filter_map]
  (let [var_in_filter (remove nil? (in-filter filter_map))
        var_out_filter (remove nil? (out-filter filter_map))]
    ;var_out_filter
    (list (in_filter_recur list1 var_in_filter)
      ;(in_filter_recur list1  var_in_filter)
      (hash-map :Other (remove nil?
                         (out_filter_recur list1 var_out_filter))))))

(defn in_filter_recur [lis in_filt]
  (if (empty? in_filt)
    nil
    (cons (hash-map
            (if ((first in_filt) 1)
              :nums
              ;"{:nums {:test number?}"
              (if ((first in_filt) 'a)
                :syms
                (if ((first in_filt) [1])
                  :vects
                  'others)))

            ;(set (merge [:data] (filter (first in_filt) lis))))
            (hash-map :test
              (if ((first in_filt) 1)
                'number?
                ;"{:nums {:test number?}"
                (if ((first in_filt) 'a)
                  'symbols?
                  (if ((first in_filt) [1])
                    'vector?
                    'others)))
              :data (filter (first in_filt) lis)))
      (in_filter_recur lis (rest in_filt)))))

(defn out_filter_recur [lis out_filt]
  (if (empty? out_filt)
    nil
    (cons ;(hash-map nil
      (if (empty? (filter (first out_filt) lis))
        nil
        (filter (first out_filt) lis))
      (out_filter_recur lis (rest out_filt)))))

(defn out-filter [filt]
  (difference 
    (set 
      (All-filter
        {:nums {:test number?}
         :syms {:test symbol?}
         :vects {:test vector?}
         :other {:test string?}})) (set (in-filter filt))))

(defn in-filter [filt]
  (list (when
          (and (> (count (str (get-in filt [:nums :test]))) 0)
            ((get-in filt [:nums :test]) 1))
          number?)
    (when
      (and (> (count (str (get-in filt [:syms :test]))) 0)
        ((get-in filt [:syms :test]) 'a))
      symbol?)
    (when
      (and (> (count (str (get-in filt [:vects :test]))) 0)
        ((get-in filt [:vects :test]) [1]))
      vector?)))



(defn All-filter [filt]
  (list (when
          (and (> (count (str (get-in filt [:nums :test]))) 0)
            ((get-in filt [:nums :test]) 1))
          number?)
    (when
      (and (> (count (str (get-in filt [:syms :test]))) 0)
        ((get-in filt [:syms :test]) 'a))
      symbol?)
    (when
      (and (> (count (str (get-in filt [:vects :test]))) 0)
        ((get-in filt [:vects :test]) [1]))
      vector?)
    (when
      (and (> (count (str (get-in filt [:other :test]))) 0)
        ((get-in filt [:other :test]) "1"))
      string?)))


(defn difference
  ([s1] s1)
  ([s1 s2]
   (if (< (count s1) (count s2))
     (reduce (fn [result item]
               (if (contains? s2 item)
                 (disj result item)
                 result))
       s1 s1)
     (reduce disj s1 s2)))
  ([s1 s2 & sets]
   (reduce difference s1 (conj sets s2))))

1 Ответ

0 голосов
/ 15 февраля 2020

Вот то, что я придумал, это своего рода специфическая c структура данных, поэтому она довольно специфична c code

Первый шаг - настроить данные так, чтобы мы могли работать с ними. merge-with

(defn get-data [val]
  (as-> val ?
        (first ?)
        (:nums ?)
        (select-keys ? [:data])))

Тогда последним шагом будет позвонить merge-with и собрать его вместе

(def x '(({:nums {:test number?, :data (1)}})
         {:Other ()} 
         ({:nums {:test number?, :data (2)}})
         ({:nums {:test number?, :data (3 4)}}))

(as-> x ? 
      (map get-data ?)
      (apply merge-with concat ?)
      (assoc ? :test 'number?)
      (list ?)
      (list ?)
      (conj ? {:Other '()})
      (reverse ?))

Если вы искали что-то более общее c, вы ' мне придётся придти мне с более общей c структурой данных.

Я думаю, то, что вы искали, в основном содержится в строке (apply merge-with concat ?), которая выполняет большую часть работы.

Эта функция берет список карт и применяет функцию, в данном случае concat к значениям в этих картах.

См. (doc merge-with) в вашем REPL для получения дополнительной информации.

Как последнее усилие, вы также можете быть заинтересованы в библиотеке specter clojure, которая превосходна в этом типе глубоко вложенного преобразования данных.

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...