在 Clojure 中使用 for 更新地图值

Updating values of map using for in Clojure

我有一个如下所示的 json 并且需要在其中添加值

{ "10 days refund": [
        {
            "paymentType": "CreditCard",
            "amount": "40$",
            "expiryDate": "20/10/2025"
        },
        {
            "paymentType": "CreditCard",
            "amount": "20$",
            "expiryDate": "20/1/2024"
        }
    ],
    "3 hours refund": [
        {
            "paymentType": "DebitCard",
            "amount": "10$",
            "expiryDate": "20/10/2026"
        },
        {
            "paymentType": "DebitCard",
            "amount": "5$",
            "expiryDate": "20/10/2027"
        }
    ]
}

在上面的地图中,我需要在每个地图类别的最后一个值中添加一个字段“message”。因此,在添加值后,我期望生成的地图如下所示

{ "10 days refund": [
            {
                "paymentType": "CreditCard",
                "amount": "40$",
                "expiryDate": "20/10/2025"
            },
            {
                "paymentType": "CreditCard",
                "amount": "20$",
                "expiryDate": "20/1/2024",
                "message" : "Refund will be processed in 10 days"
            }
        ],
        "3 hours refund": [
            {
                "paymentType": "DebitCard",
                "amount": "10$",
                "expiryDate": "20/10/2026"
            },
            {
                "paymentType": "DebitCard",
                "amount": "5$",
                "expiryDate": "20/10/2027",
                "message" : "Refund will be processed in 3 hours"
            }
        ]
    }

我试过用下面的方法实现它

(defn ^:private payment-methods
  [pm-sorted]
  (let [categories (group-by pm-fingerprint pm-sorted)]
    (for [[pm-fingerprint pm-sorted] categories
          :let [last-payment-method (last pm-sorted)
                dropped-last (drop-last pm-sorted)]]
      (if (= (:refund-category pm-fingerprint) "10 hours refund")
        ((println "10 days refund")
         (doall (conj (doall dropped-last) (assoc last-payment-method :message
                                                                      (text (str "Refund will be processed in 10 days"))))))
        ((println "3 hours refund")
         (doall (conj (doall dropped-last) (assoc last-payment-method :message
                                                                      (text (str "Refund will be processed in 3 hours"))))))))))

(defn ^:private pm-fingerprint
  [payment-method]
  (let [payment-type ("paymentType" payment-method)]
    {:refund-category (if (= payment-type "CreditCard"))
                     "10 days refund"
                     "3 hours refund")}))

我希望通过执行函数得到的结果输出是一个如下所示的向量

[
{
                    "paymentType": "CreditCard",
                    "amount": "40$",
                    "expiryDate": "20/10/2025"
                },
                {
                    "paymentType": "CreditCard",
                    "amount": "20$",
                    "expiryDate": "20/1/2024",
                    "message" : "Refund will be processed in 10 days"
                }
                {
                    "paymentType": "DebitCard",
                    "amount": "10$",
                    "expiryDate": "20/10/2026"
                },
                {
                    "paymentType": "DebitCard",
                    "amount": "5$",
                    "expiryDate": "20/10/2027",
                    "message" : "Refund will be processed in 3 hours"
                }
            ]

并且由于没有返回任何值,所以我得到 null 作为输出。有人可以帮忙解决这个问题吗?

这是一个有效的例子。一、声明&数据:

(ns tst.demo.core
  (:use tupelo.core tupelo.test)
  (:require
    [schema.core :as s]
    [tupelo.string :as str]
  ))

(def input
  (str/quotes->double
    "{ '10-days-refund': [
            { 'paymentType': 'CreditCard',
                'amount': '40$',
                'expiryDate': '20/10/2025' },
            { 'paymentType': 'CreditCard',
                'amount': '20$',
                'expiryDate': '20/1/2024' }
        ],
        '3-hours-refund': [
            {
                'paymentType': 'DebitCard',
                'amount': '10$',
                'expiryDate': '20/10/2026' },
            { 'paymentType': 'DebitCard',
                'amount': '5$',
                'expiryDate': '20/10/2027' } ] }"))

然后处理:

(dotest
  (let [data  (json->edn input)
        data2 (vec
                (for [entry data]
                  (let [[the-key pmt-lst] entry ; destruture into key and list of vals
                        pmt-lst-butlast   (butlast pmt-lst)
                        pmt-lst-last      (last pmt-lst)
                        last-new          (assoc pmt-lst-last :message "Coming Soon!")
                        pmt-lst-new       (append pmt-lst-butlast last-new)
                        entry-new         [the-key pmt-lst-new]]
                    entry-new)))]

验证结果:

    (is= data2
         [[:10-days-refund
           [{:amount "40$" :expiryDate "20/10/2025" :paymentType "CreditCard"}
            {:amount      "20$"
             :expiryDate  "20/1/2024"
             :message     "Coming Soon!"
             :paymentType "CreditCard"}]]
          [:3-hours-refund
           [{:amount "10$" :expiryDate "20/10/2026" :paymentType "DebitCard"}
            {:amount      "5$"
             :expiryDate  "20/10/2027"
             :message     "Coming Soon!"
             :paymentType "DebitCard"}]]]
    )))

请参阅文档列表 in this template project,尤其是 Clojure CheatSheet。