2017-03-27 21 views
0

2つのベクトルを比較しようとすると、その差を別のベクトルに格納しようとします。オブジェクト内のIFステートメント内にネストされた結果を格納する

;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" }} 

私は、ネストされたdoseqを用いた論理を構築しようとしているが、私はClojureの内の変数に書き込む方法がわからない

{{: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"     }} 

のような出力を取得しようとしています。

(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に関してnewbです:(

+0

あなたのデータはトップレベルのマップです。それらは集合(またはベクトルまたはリストまたは...)でなければなりません。 – Thumbnail

答えて

1

事はdoseqあなたのケースでは、あなたは何か可変変数に何かを入れる必要はありません。その結果、それはリストの内包(for)を使用することです行うための方法の一つ:。

(defn compare-data [data1 data2] 
    (for [recent-item data1 
     old-item data2 
     :when (= (:SKU recent-item) (:SKU old-item)) 
     :let [[old-file new-file] (clojure.data/diff recent-item old-item) 
       current-sku (:SKU recent-item)]] 
    {:SKU current-sku :reason ...})) 

(それをテストするための任意の時間を持っていなかったが、それでもそれが動作するはずです)

+0

「理由:欠落|追加」シナリオを考えましたか? –

+0

nope。これは、概念的にそれを行う方法についての質問だったので、opのアプローチのむしろより慣用的な転記です。それでも、この方法では、追加のロジックに 'for'マクロの': 'ブロックを追加することができます – leetwinski

0

注文事項をいあなたのベクタには?もしそうでない場合(おそらく、あなたはインデックス作成のためにSKUを使用しているようです)、最初にそれらをマップに変換してくださいO(n^2)ループを無効にして、各SKUをそれぞれ比較します。

(defn dataset->map [dataset] 
    (into {} (for [rec dataset] [(:SKU rec) (dissoc rec :SKU)]))) 

あなたは、2つのマップのキーリストをマージして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 

上記のコードは、あなたが望む形式でリストを返す必要があります。

0

データには2つの問題があります。第1に、ベクトルは、ポジションではなく、関連性のあるデータを格納するのに適した方法ではありません。次に、数量ゼロに対して「在庫切れ」を、ゼロより大きい数量に対して「在庫あり」を保管するため、派生する重複情報を保管しています。多くのアイテムを持つ大規模なシステムでは、このように派生可能なデータをキャッシュするのは問題ありませんが、この場合、単に不必要な冗長性に過ぎません。だから、あなたは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}}) 

この関数は、ここで提案するデータ構造で、あなたが望む比較を行います。最初に、diffを追加して削除する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"}} 

これは、最初に使用したベクターを使用していないが、明らかにベクトルが右のデータ構造ではない、と連想1がより適切です。

関連する問題