Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/flash/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 在嵌套映射中重塑/连接/展平数据的声明方式_Clojure - Fatal编程技术网

Clojure 在嵌套映射中重塑/连接/展平数据的声明方式

Clojure 在嵌套映射中重塑/连接/展平数据的声明方式,clojure,Clojure,我正在寻找一种在Clojure中进行以下数据转换的好的声明方式。我完全可以利用任何一个数据转换库,但我希望得到建议。我已经研究了曲流、轨迹、DataScript和其他,但还没有找到最合适的。 随着输入数据的复杂性/嵌套的增加,香草Clojure变得非常难看,变得非常必要 ;; my input data (def db {:items [{:id 1 :labels [1 2 3]} {:id 2 :labels [2]}

我正在寻找一种在Clojure中进行以下数据转换的好的声明方式。我完全可以利用任何一个数据转换库,但我希望得到建议。我已经研究了曲流、轨迹、DataScript和其他,但还没有找到最合适的。 随着输入数据的复杂性/嵌套的增加,香草Clojure变得非常难看,变得非常必要


;; my input data
(def db {:items  [{:id 1 :labels [1 2 3]}
                  {:id 2 :labels [2]}
                  {:id 3 :labels []}
                  {:id 4 :labels nil}
                  {:id 5 }]
         :labels [{:id 1 :name "one"}
                  {:id 2 :name "two"}
                  {:id 3 :name "three"}
                  {:id 4 :name "four"}]})

;; what to do here
(defn flatten-labels [d]
  ???)

;; so that I get this
(flatten-labels db)
;; =>
;; {:items
;; [{:id 1 :labels ["one" "two" "three"]}
;;  {:id 2 :labels ["two"]}
;;  {:id 3 :labels []}
;;  {:id 4 :labels []}
;;  {:id 5 :labels []}]}


编辑:

(defn flatten-labels [{:keys [items labels]}]
  (let [->indexed-maps-by (fn [v idx]
                            (into {} (map #(hash-map (get % idx) %)) v))
        label-db          (->indexed-maps-by labels :id)
        label-lookup      (fn [lid] (get-in label-db [lid :name]))
        ]
    (map #(update % :labels (fn [lids] (mapv label-lookup lids))) items)
    )
  )

这是我的香草溶液,供参考。 基本上,我正在以正确的形状构造一个“查找表”,然后(映射…(更新…(映射…))转换嵌套序列的元素

我主要担心的是,这有点过于循序渐进,如果我可以用声明的方式表达相同的成形/转换,这将使它更容易发生变化,更容易推广到更复杂的数据集,所有这些“通过某个关键点在某个地方解决某个问题并将其拉到这里”情况


感谢迄今为止的所有推荐,非常感谢

类似的内容可能会有所帮助:

(let [labels (->> db :labels (map (juxt :id :name)) (into {}))
      relabel (fn [item] (update item :labels (partial mapv labels)))]
  (update db :items (partial mapv relabel)))
虽然它不够通用,但它仍然解决了这个任务

更通用的变体是使用:


类似的内容可能会有所帮助:

(let [labels (->> db :labels (map (juxt :id :name)) (into {}))
      relabel (fn [item] (update item :labels (partial mapv labels)))]
  (update db :items (partial mapv relabel)))
虽然它不够通用,但它仍然解决了这个任务

更通用的变体是使用:


因为你特别要求一些声明性的东西,你可以试着强迫自己去做你想做的事情。但是规范的定义将取决于输入数据,即
:labels
键处的值。我不会说这是一个解决问题的好方法,但如果这是您所寻找的,那么它可以说是相当声明性的。您需要一个动态变量,
标签数据
,以使此方法有效,还需要一个自定义的一致性变量,
标签索引
。其余的只是数据库的常规规范。大概是这样的:

(require '[clojure.spec.alpha :as spec])

(def ^:dynamic label-data {0 "test"})

(defn index-to-label [index]
  (get label-data index ::spec/invalid))

(spec/def ::labels (spec/nilable (spec/coll-of (spec/conformer index-to-label))))
(spec/def ::id number?)
(spec/def ::items (spec/coll-of (spec/keys :req-un [::id] :opt-un [::labels])))
(spec/def ::db (spec/keys :req-un [::items]))

(defn flatten-labels [db]
  (binding [label-data (into {} (for [x (:labels db)] [(:id x) (:name x)]))]
    (spec/conform ::db db)))
这是我们在您的数据上试用时得到的结果:

(flatten-labels db)
;; => {:items [{:id 1, :labels ["one" "two" "three"]} {:id 2, :labels ["two"]} {:id 3, :labels []} {:id 4, :labels nil} {:id 5}], :labels [{:id 1, :name "one"} {:id 2, :name "two"} {:id 3, :name "three"} {:id 4, :name "four"}]}

因为你特别要求一些声明性的东西,你可以试着强迫自己去做你想做的事情。但是规范的定义将取决于输入数据,即
:labels
键处的值。我不会说这是一个解决问题的好方法,但如果这是您所寻找的,那么它可以说是相当声明性的。您需要一个动态变量,
标签数据
,以使此方法有效,还需要一个自定义的一致性变量,
标签索引
。其余的只是数据库的常规规范。大概是这样的:

(require '[clojure.spec.alpha :as spec])

(def ^:dynamic label-data {0 "test"})

(defn index-to-label [index]
  (get label-data index ::spec/invalid))

(spec/def ::labels (spec/nilable (spec/coll-of (spec/conformer index-to-label))))
(spec/def ::id number?)
(spec/def ::items (spec/coll-of (spec/keys :req-un [::id] :opt-un [::labels])))
(spec/def ::db (spec/keys :req-un [::items]))

(defn flatten-labels [db]
  (binding [label-data (into {} (for [x (:labels db)] [(:id x) (:name x)]))]
    (spec/conform ::db db)))
这是我们在您的数据上试用时得到的结果:

(flatten-labels db)
;; => {:items [{:id 1, :labels ["one" "two" "three"]} {:id 2, :labels ["two"]} {:id 3, :labels []} {:id 4, :labels nil} {:id 5}], :labels [{:id 1, :name "one"} {:id 2, :name "two"} {:id 3, :name "three"} {:id 4, :name "four"}]}
帮助函数 解函数 试试看 帮助函数 解函数 试试看
使用
clojure.set:as set

(让[db{:items[{:id 1:labels[1 2 3]}
{:ID2:标签[2]}
{:id 3:标签[]}
{:id 4:labels nil}
{:ID5}]
:labels[{:id 1:name“one”}
{:ID2:name“two”}
{:ID3:name“three”}
{:ID4:name“four”}]}]
(设置/连接)
(->db:项目集)
(->db:标签集)
{:id:id})
=>
#{{:ID4,:name“four”,:labels nil}
{:id 3,:name“three”,:labels[]}
{:id 1,:name“one”,:labels[1 2 3]}
{:ID2,:name“two”,:labels[2]}
另一个,仅使用
clojure.core

(让[db{:items[{:id 1:labels[1 2 3]}
{:ID2:标签[2]}
{:id 3:标签[]}
{:id 4:labels nil}
{:ID5}]
:labels[{:id 1:name“one”}
{:ID2:name“two”}
{:ID3:name“three”}
{:ID4:name“four”}]}]
(reduce(fn[idx{:keys[id]:as value})
(更新idx id合并值))
{}
;;;(concat(:items db)(:items db))
(mapcat val db)))
=>
{1{:ID1,:labels[1233],:name“one”},
2{:ID2,:labels[2],:name“two”},
3{:ID3,:labels[],:name“three”},
4{:ID4,:labels nil,:name“four”},
5{:ID5}

只是一个注释,我认为您应该使用
{:table name{idx{:key:value}}}
格式,就像
fulcro
使用一样。

使用
clojure.set:as-set

(让[db{:items[{:id 1:labels[1 2 3]}
{:ID2:标签[2]}
{:id 3:标签[]}
{:id 4:labels nil}
{:ID5}]
:labels[{:id 1:name“one”}
{:ID2:name“two”}
{:ID3:name“three”}
{:ID4:name“four”}]}]
(设置/连接)
(->db:项目集)
(->db:标签集)
{:id:id})
=>
#{{:ID4,:name“four”,:labels nil}
{:id 3,:name“three”,:labels[]}
{:id 1,:name“one”,:labels[1 2 3]}
{:ID2,:name“two”,:labels[2]}
另一个,仅使用
clojure.core

(让[db{:items[{:id 1:labels[1 2 3]}
{:ID2:标签[2]}
{:id 3:标签[]}
{:id 4:labels nil}
{:ID5}]
:labels[{:id 1:name“one”}
{:ID2:name“two”}
{:ID3:name“three”}
{:ID4:name“four”}]}]
(reduce(fn[idx{:keys[id]:as value})
(更新idx id合并值))
{}
;;;(concat(:items db)(:items db))
(mapcat val db)))
=>
{1{:ID1,:labels[1233],:name“one”},
2{:ID2,:labels[2],:name“two”},
3{:ID3,:labels[],:name“three”},
4{:ID4,:labels nil,:name“four”},
5{:ID5}

只是一个注释,我认为您应该使用
{:table name{idx{:key:value}}}
格式,就像
fulcro
使用一样。

请添加您尝试过的代码以及失败的原因(例如错误、堆栈跟踪、日志等),以便我们可以对其进行改进。我有一个工作原理
(def db {:items  [{:id 1 :labels [1 2 3]}
                  {:id 2 :labels [2]}
                  {:id 3 :labels []}
                  {:id 4 :labels nil}
                  {:id 5 }]
         :labels [{:id 1 :name "one"}
                  {:id 2 :name "two"}
                  {:id 3 :name "three"}
                  {:id 4 :name "four"}]})

(flatten-labels db)
;; {:items [{:id 1, :labels ["one" "two" "three"]}
;;          {:id 2, :labels ["two"]} 
;;          {:id 3, :labels []} 
;;          {:id 4, :labels []} 
;;          {:id 5, :labels []}]}