簡體   English   中英

如何根據鍵名有條件地更新 Clojure map 中的鍵和值?

[英]How do I conditionally update keys and values in a Clojure map based on the key name?

我有一個 map,鍵是字符串。 如果密鑰包含單詞“kg”,我想將該值乘以 2.2,然后將密鑰中的“kg”替換為“lb”。 我不知道如何以可以有條件地更新它的方式迭代 map。

示例 map:

{"id" ("7215" "74777" "7219"),
 "weight-kg" ("150" "220" "530"),
 "time-seconds" ("1900" "2" "770")}

所需 output

{"id" ("7215" "74777" "7219"),
 "weight-lb" ("330" "485" "1168"),
 "time-seconds" ("1900" "2" "770")}

我試過update for mapreduce-kv 項目需求是不使用字符串庫,所以才會有re-find 這些只是改變價值觀的嘗試。 由於我無法更改值,因此我沒有嘗試更改密鑰。

(defn kg->lb [m k]
    (if (re-find #"kg" k)
      (map #(update m % * 2.2))))

(defn kg2->lb2 [m]
    (reduce-kv #(if (re-find #"kg" %)
                  (update % * 2.2)) {} m)

(map #(if (re-find #"kg" %)
        (update % * 2.2)) m)

(for [k (keys m)]
    (if (re-find #"kg" k)
      (update m k #(* % 2.2))))

數據:

(def data {"id"           ["7215" "74777" "7219"],
           "weight-kg"    ["150" "220" "530"],
           "time-seconds" ["1900" "2" "770"]})

助手 function 將字符串(kg 數量)轉換為字符串(lb 數量):

(defn kg->lb [kg-string]
  (-> kg-string
      parse-long
      (* 2.2)
      int
      str))

最重要的 function 是reduce-kv

如果您在鍵中找到"kg" ,您將用"lb"和 map helper function 替換所有值。

如果您在密鑰中沒有找到"kg" ,您將直接關聯該條目而無需更改。

(reduce-kv (fn [m k v]
             (if (re-find #"kg" k)
               (assoc m (str/replace k #"kg" "lb")
                        (map kg->lb v))
               (assoc m k v)))
           {} 
           data)

我想我通過了項目要求是不使用字符串庫,除了(str/replace k #"kg" "lb") ,你可以用String/replace interop: (.replace k "kg" "lb")

編輯:解決方案mapinto

(defn update-entry [[k v]]
  (if (re-find #"kg" k)
    [(.replace k "kg" "lb") (map kg->lb v)]
    [k v]))

(->> data
     (map update-entry)
     (into {}))

傳感器版本:

(into {} (map update-entry) data)

我會做一些不同的。 首先,我使用 Java function Long/parseLong將字符串轉換為整數:

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test)
  (:require
    [tupelo.core :as t]
    ))

(defn parse-vec-longs
  [v]
  (mapv #(Long/parseLong %) v))

(verify
  (is= (parse-vec-longs ["150" "220" "530"])
    [150 220 530]))

然后我會編寫代碼將 kg vals 轉換為 lb vals。 最后,只需使用dissoc去掉 kg 數據,然后assoc添加新的 lb 數據:

(defn convert-kg-lb
  [data]
  (let-spy-pretty [kg-vals (get data "weight-kg")
                   lb-vals (mapv #(Math/round (* 2.2 %)) kg-vals)
                   result  (t/it-> data
                             (dissoc it "weight-kg")
                             (assoc it "weight-lb" lb-vals))]
    result))

(verify
  (let [data-str        {"id"           ["7215" "74777" "7219"]
                         "weight-kg"    ["150" "220" "530"]
                         "time-seconds" ["1900" "2" "770"]}
        data-parsed     (t/map-vals data-str #(parse-vec-longs %))
        expected-parsed {"id"           [7215 74777 7219]
                         "weight-kg"    [150 220 530]
                         "time-seconds" [1900 2 770]}
        expected-out    {"id"           [7215 74777 7219]
                         "weight-lb"    [330 484 1166]
                         "time-seconds" [1900 2 770]}
        result          (convert-kg-lb data-parsed)]
    (is= data-parsed expected-parsed)
    (is= (spyx-pretty result) (spyx-pretty expected-out))))

通常,您還會用關鍵字替換所有字符串鍵,因此"lb" => :lb

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM