[英]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.