在 Clojure 中使用 for 更新地图的值

问题描述

我有一个像下面这样的 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"
        }
    ]
}

在上面的地图中,我需要在每个地图类别的最后一个值中添加一个字段“消息”。因此,在添加值后,我期望得到如下所示的结果地图

{ "10 days refund": [
            {
                "paymentType": "CreditCard","expiryDate": "20/10/2025"
            },{
                "paymentType": "CreditCard","expiryDate": "20/1/2024","message" : "refund will be processed in 10 days"
            }
        ],"3 hours refund": [
            {
                "paymentType": "DebitCard","expiryDate": "20/10/2026"
            },{
                "paymentType": "DebitCard","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","expiryDate": "20/10/2025"
                },{
                    "paymentType": "CreditCard","message" : "refund will be processed in 10 days"
                }
                {
                    "paymentType": "DebitCard","expiryDate": "20/10/2026"
                },{
                    "paymentType": "DebitCard","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。