Clojure中如何遍历列表映射替换客户/产品ID为对应名称?
问题描述
我已经把文本文件转换成了几个映射结构:
客户信息映射
{1 (John Smith 123 Here Street 456-4567), 2 (Sue Jones 43 Rose Court Street 345-7867), 3 (Fan Yuhong 165 Happy Lane 345-4533)}
产品信息映射
{1 (shoes 14.96), 2 (milk 1.98), 3 (jam 2.99), 4 (gum 1.25), 5 (eggs 2.98), 6 (jacket 42.99)}
交易记录映射
键为记录ID,值为[客户ID 产品ID 购买数量]:
{1 (1 1 3), 2 (2 2 3), 3 (2 1 1), 4 (3 3 4)}
我的需求是把交易记录里的客户ID替换成对应客户姓名,产品ID替换成对应产品名称。试过两段代码但效果不好:
(map #(clojure.edn/read-string (first %)) items)
还有:
(defn update-map [m f] (reduce-kv (fn [m k v] (assoc m k (f v))) {} m))
之前以为递归是遍历映射的唯一方式,但不知道怎么在嵌套结构里做元素替换,求帮助。
解决方案
首先先把映射定义为合法的Clojure数据结构(用字符串包裹文本避免符号解析问题):
;; 客户映射:键为客户ID,值的第一个元素是姓名 (def customers {1 ["John Smith" "123 Here Street" "456-4567"], 2 ["Sue Jones" "43 Rose Court Street" "345-7867"], 3 ["Fan Yuhong" "165 Happy Lane" "345-4533"]}) ;; 产品映射:键为产品ID,值的第一个元素是产品名 (def products {1 ["shoes" 14.96], 2 ["milk" 1.98], 3 ["jam" 2.99], 4 ["gum" 1.25], 5 ["eggs" 2.98], 6 ["jacket" 42.99]}) ;; 交易记录 (def transactions {1 [1 1 3], 2 [2 2 3], 3 [2 1 1], 4 [3 3 4]})
接下来用reduce-kv结合简单的取值逻辑就能完成替换,不需要复杂递归:
(defn enrich-transactions [txns custs prods] (reduce-kv (fn [acc txn-id [cust-id prod-id qty]] ;; 从客户映射取姓名,产品映射取名称 (assoc acc txn-id [(first (custs cust-id)) (first (prods prod-id)) qty])) {} txns)) ;; 调用函数查看结果 (enrich-transactions transactions customers products)
执行后会得到目标结果:
{1 ["John Smith" "shoes" 3], 2 ["Sue Jones" "milk" 3], 3 ["Sue Jones" "shoes" 1], 4 ["Fan Yuhong" "jam" 4]}
补充说明
- 你写的
update-map函数本身没问题,只是需要给f传入能处理交易记录值的逻辑——也就是从两个映射中取出对应名称的函数。 - 不需要手动调用
clojure.edn/read-string,只要初始映射是合法的Clojure数据结构,直接通过键取值即可。 - 如果原始映射必须保留列表结构,把取值逻辑改成
(first (get custs cust-id))即可,核心逻辑不变。
内容的提问来源于stack exchange,提问作者lcdlv
相关产品推荐
相关产品推荐

