繁体   English   中英

如何在Clojure中合并两个地图列表

[英]How to merge two lists of maps in Clojure

我有以下格式的数据。

'(({: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 ()})

尝试使用合并、联合功能,但没有奏效。 你能在这里帮忙吗,因为我是 Closure 的初学者。

对以下代码进行测试

(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))))

这是我想出的,它是一种特定的数据结构,所以它是非常具体的代码

第一步是设置数据,以便我们可以使用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 ?))

如果您正在寻找更通用的东西,您将不得不使用更通用的数据结构来找我。

我认为您要查找的内容主要包含在执行大部分工作的(apply merge-with concat ?)行中。

这个函数接受一个映射列表并应用该函数,在这种情况下concat到这些映射中的值。

有关更多信息,请参阅 REPL 中的(doc merge-with)

作为最后的努力,您可能还对Spectre clojure 库感兴趣,它擅长这种深度嵌套的数据转换。

希望这可以帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM