在clojure中的IF语句中存储嵌套结果

在clojure中的IF语句中存储嵌套结果,clojure,Clojure,尝试比较两个向量,并将差异存储在另一个向量中 ;Data Set 1 {{:SKU "Apple" :QTY 10 :Status "In Stock" } {:SKU "Banana" :QTY 10 :Status "In Stock" } {:SKU "Mango" :QTY 0 :Status "Out of stock"} {:SKU "XYZ" :QTY 10 :Status "In Stock"

尝试比较两个向量,并将差异存储在另一个向量中

;Data Set 1
{{:SKU "Apple"      :QTY 10    :Status "In Stock"    }
 {:SKU "Banana"     :QTY 10    :Status "In Stock"    }
 {:SKU "Mango"      :QTY 0     :Status "Out of stock"}
 {:SKU "XYZ"        :QTY 10    :Status "In Stock"    }
 {:SKU "Grapes"     :QTY 10    :Status "In Stock"    }}

;Data Set 2
{{:SKU "Apple"      :QTY 5     :Status "In Stock"    }
 {:SKU "Banana"     :QTY 0     :Status "Out of Stock"}
 {:SKU "Mango"      :QTY 10    :Status "In Stock"    }
 {:SKU "XYZ"        :QTY 10    :Status "In Stock"    }
 {:SKU "Pineapple"  :QTY 10    :Status "In Stock"    }}
我想得到一个像这样的输出

{{:SKU "Apple"      :Reason "Stock Change -5"        }
 {:SKU "Banana"     :Reason "In Stock +10"           }
 {:SKU "Mango"      :Reason "Out of stock -10"       }
 {:SKU "Grapes"     :Reason "Missing"                }
 {:SKU "Pineapple"  :Reason "Added"                  }}
我试图使用嵌套的doseq构建逻辑,但我不知道如何将其写入clojure中的变量

(defn compare_two_vectors
[data_set1 data_set2]
(doseq [recent_item data_set1]
  (doseq [old_item data_set2]
    (if (= (recent_item :SKU) (old_item :SKU))
      (let [diffresults (clojure.data/diff recent_item old_item)
            old_file (second diffresults)
            new_file (first diffresults)
            current_sku (recent_item :SKU)
            ]
            ;; How do I store results into a persistant variable?
        )))))
那我就可以了

(println (compare_two_vectors data_set1 data_set2))
更新:或者让我知道什么是更好的选择。关于clojure,我还是个新手:。

问题是doseq用于治疗副作用。在您的情况下,您不需要将任何内容放入某个可变变量中。相反,您可以映射集合并返回结果。其中一种方法是使用列表理解:


没有时间测试它,但仍然应该可以

在向量中顺序重要吗?如果没有,可能是这种情况-您似乎正在使用SKU进行索引,最好先将它们转换为映射,以避免在^2循环中将每个SKU与每个SKU进行比较

(defn dataset->map [dataset]
  (into {} (for [rec dataset] [(:SKU rec) (dissoc rec :SKU)])))
然后,通过合并两个映射的密钥列表并应用clojure.core/distinct,您可以获得第一个数据集中或第二个数据集中的所有SKU的列表,或者两者都有

使用此功能,您可以循环所有SKU以获得所需:

(defn compare-data [dataset-vec-1 dataset-vec-2]
  (let [dataset-1 (dataset->map dataset-vec-1)
        dataset-2 (dataset->map dataset-vec-2)
        all-SKUs (distinct (concat (keys dataset-1) (keys dataset-2)))]
    (for [sku all-SKUs
          :let [rec-1 (get dataset-1 sku)
                rec-2 (get dataset-2 sku)]]
      {:SKU    sku
       :reason (cond
                 (nil? rec-1) "Added"
                 (nil? rec-2) "Missing"
                 :else ...)}))) ; whatever else you need to generate the reason

上面的代码应该以您想要的格式返回列表。

您的数据有两个问题。首先,向量不是存储数据的好方法,因为这些数据不是位置数据,而是关联数据。第二,您存储的是可以派生的冗余信息,因为您存储的是数量为零的缺货信息,以及数量大于零的库存信息。在具有许多项的大型系统中,可以通过这种方式缓存可派生数据,但在这种情况下,这只是不必要的冗余。因此,您最好这样定义数据,IMO:

(def ds1 {"Apple"  {:QTY 10}
          "Banana" {:QTY 10}
          "Mango"  {:QTY 0}
          "XYZ"    {:QTY 10}
          "Grapes" {:QTY 10}})

(def ds2 {"Apple"     {:QTY 5}
          "Banana"    {:QTY 0}
          "Mango"     {:QTY 10}
          "XYZ"       {:QTY 10}
          "Pineapple" {:QTY 10}})
此函数将与此处建议的数据结构进行比较。首先,它进行差异分析,以确定添加和删除的SKU。接下来,它对两者中存在的项进行差异,并使用合并函数计算差异

(defn sku-diff [sku-before sku-after]
  (let [[removed added _] (d/diff (set (keys sku-before)) (set (keys sku-after)))
        removed-map (apply hash-map (concat (interpose {:Status "Missing"} removed)
                                            [{:Status "Missing"}]))
        added-map (apply hash-map (concat (interpose {:Status "Added"} added)
                                          [{:Status "Added"}]))

        [before after _] (d/diff sku-before sku-after)
        before (apply dissoc before removed)
        after (apply dissoc after added)

        merge-fn (fn [{before-qty :QTY} {after-qty :QTY}]
                   (let [stock-change (- after-qty before-qty)
                         text (cond (zero? before-qty) "In Stock +"
                                    (zero? after-qty) "Out of stock "
                                    :default "Stock Change ")]
                     {:Status (str text stock-change)}))

        changed-map (merge-with merge-fn before after)]

    (merge removed-map added-map changed-map)))
结果是:

(sku-diff ds1 ds2)
=>
{"Pineapple" {:Status "Added"},
 "Mango"     {:Status "In Stock +10"},
 "Grapes"    {:Status "Missing"},
 "Apple"     {:Status "Stock Change -5"},
 "Banana"    {:Status "Out of stock -10"}}

这不是使用您最初使用的向量,但显然向量不是正确的数据结构,而关联的数据结构更合适。

您考虑过原因吗:缺少|添加的场景?没有。这是对op方法的一种更为惯用的转录,因为问题是如何在概念上做到这一点。尽管如此,这种方法仍然允许添加更多的附加逻辑:当宏数据中的块是顶层的映射时。它们应该是集合、向量、列表或。。。。
(sku-diff ds1 ds2)
=>
{"Pineapple" {:Status "Added"},
 "Mango"     {:Status "In Stock +10"},
 "Grapes"    {:Status "Missing"},
 "Apple"     {:Status "Stock Change -5"},
 "Banana"    {:Status "Out of stock -10"}}