clojure爬坑之项目里处理过的复杂逻辑


简书地址

1、一个高阶函数的使用:将db查询结果日期进行format,并且group和求sum,重新组织结构

从DB中查到的map结果集如下:

(alk-wxapi.db.db-patient/get-patient-cost
  {:page       0,
   :size       10,
   :patient-id 222})
=>
({:deleted 0,
  :drug-flag 1,
  :drug-id 1,
  :cost-date #object[java.time.LocalDate 0x2d30b554 "2019-05-07"],
  :id "1",
  :create-time #object[java.time.LocalDateTime 0x76211aed "2019-06-05T22:42:14"],
  :count 2,
  :drug-name "安脱达",
  :patient-id "222",
  :sum 58.0}
 {:deleted 0,
  :drug-flag 1,
  :drug-id 1,
  :cost-date #object[java.time.LocalDate 0x9e55443 "2019-06-05"],
  :id "3",
  :create-time #object[java.time.LocalDateTime 0x7114ec3c "2019-06-05T22:42:01"],
  :count 10,
  :drug-name "安脱达",
  :patient-id "222",
  :sum 120.0}
 {:deleted 0,
  :drug-flag 1,
  :drug-id 4,
  :cost-date #object[java.time.LocalDate 0x59267d5f "2019-05-07"],
  :id "2",
  :create-time #object[java.time.LocalDateTime 0x27aef2e4 "2019-06-05T22:41:50"],
  :count 15,
  :drug-name "奥马珠",
  :patient-id "222",
  :sum 200.0})

json以后格式是一条条的record:

"data": [
      {
        "deleted": 0,
        "drug-flag": 1,
        "drug-id": 1,
        "cost-date": "2019-05-07",
        "id": "1",
        "create-time": "2019-06-05T22:42:14",
        "count": 2,
        "drug-name": "安脱达",
        "patient-id": "222",
        "sum": 58
      },
      {
        "deleted": 0,
        "drug-flag": 1,
        "drug-id": 1,
        "cost-date": "2019-06-05",
        "id": "3",
        "create-time": "2019-06-05T22:42:01",
        "count": 10,
        "drug-name": "安脱达",
        "patient-id": "222",
        "sum": 120
      },
      {
        "deleted": 0,
        "drug-flag": 1,
        "drug-id": 4,
        "cost-date": "2019-05-07",
        "id": "2",
        "create-time": "2019-06-05T22:41:50",
        "count": 15,
        "drug-name": "奥马珠",
        "patient-id": "222",
        "sum": 200
      }
    ]

而预期的json是干这么几件事:

1、根据日期将分组,以指定字段为key,group的日期为value
2、对日期进行格式化
3、同一日期下的数据,以list为key,record作为value
4、对每个list里record的sum字段求和,与list同级,以total-cost为key,和为value
5、同4类似,对list里的record的count求和,与list同级,以total-count为key,和为value

{
"content": [
      {
        "cost-date": "2019-05-07",
        "list": [
          {
            "deleted": 0,
            "drug-flag": 1,
            "drug-id": 1,
            "cost-date": "2019-05-07",
            "id": "1",
            "create-time": "2019-06-05T22:42:14",
            "count": 2,
            "drug-name": "安脱达",
            "patient-id": "222",
            "sum": 58
          },
          {
            "deleted": 0,
            "drug-flag": 1,
            "drug-id": 4,
            "cost-date": "2019-05-07",
            "id": "2",
            "create-time": "2019-06-05T22:41:50",
            "count": 15,
            "drug-name": "奥马珠",
            "patient-id": "222",
            "sum": 200
          }
        ],
        "total-cost": 258,
        "total-count": 17
      },
      {
        "cost-date": "2019-06-05",
        "list": [
          {
            "deleted": 0,
            "drug-flag": 1,
            "drug-id": 1,
            "cost-date": "2019-06-05",
            "id": "3",
            "create-time": "2019-06-05T22:42:01",
            "count": 10,
            "drug-name": "安脱达",
            "patient-id": "222",
            "sum": 120
          }
        ],
        "total-cost": 120,
        "total-count": 10
      }
    ]
}

那么这个处理函数应该怎么写呢?
提供一个工具类,处理将关系数据库的record搞成tree的函数

(defn group-data-by-keys
  "对一组数据库返回结果{data}进行处理, 使用{group-keys}中的key进行group-by:
  (sut/group-data-by-keys test-dict
                                  [:group-code1
                                   :group-code2]
                                  )
  可以带多组额外的集合函数,多组[key reducing-function init-value]的格式:
  (sut/group-data-by-keys test-dict
                                  [:group-code]

                                  :a
                                  (fn [v e] (+ v (:id e)))
                                  0

                                  :b
                                  (fn [v e] (+ v (:id e)))
                                  0
                                  )"
  ([data group-keys]
   (->> data
        (group-by (fn [m] (select-keys m group-keys)))

        (reduce-kv (fn [m k v]
                     (assoc m k {:list
                                 (mapv
                                  (fn [e]
                                    (apply dissoc e group-keys))
                                  v)}))
                   {})
        (mapv (fn [e] (apply merge e)))))

  ([data group-keys key r-func val & krvs]
   (->> data
        (group-by (fn [m] (select-keys m group-keys)))

        (reduce-kv (fn [m k v]
                     (assoc m
                            k (if (empty? krvs)
                                {:list
                                 (mapv
                                  (fn [e]
                                    (apply dissoc e group-keys))
                                  v)
                                 key (reduce r-func val v)}

                                (apply assoc {:list
                                              (mapv
                                               (fn [e]
                                                 (apply dissoc e group-keys))
                                               v)
                                              key (reduce r-func val v)}


                                       (let [krvs-seq (partition 3 krvs)]
                                         (mapcat (fn [krv]
                                                   (let [[key r-func val] krv]
                                                     [key (reduce r-func val v)]))
                                                 krvs-seq))))))

                   {})
        (map (fn [e] (apply merge e))))))

在提供一个相反作用的函数

(defn list-from-group-by
 "去除分组, 作用和group-data-by-key 相反:
  一层嵌套: (list-from-group-by {:y 1 :a [{:b 2} {:b 3}]} )))  ->  [{:b 2, :y 1} {:b 3, :y 1}]


 双层嵌套:  (mapcat sut/list-from-group-by
                  (sut/list-from-group-by {:y 1 :a [{:b [{:x 99}]} {:b [{:x 77}]}]} ))

           ->

           [{:x 99, :y 1} {:x 77, :y 1}]
 "
 [m]
 (reduce-kv (fn [r k v]
             (if (vector? v)
              (->> (apply conj r v)
                   (map #(merge % (dissoc m k))))

              r))

            []
            m))

2、一些有用的utils


(defn lower-case-keywrod
 "把输入的字符串变成keywrokd \"ABC\" -> :abc "
 [s]
 (keyword (clojure.string/lower-case s)))


(defn parse-int
  "string 转 int"
  [s]
  (Integer/parseInt (re-find #"\A-?\d+" s)))

(defn parse-double
  "string 转 doule"
  [s]
  (Double/parseDouble (re-find #"\A-?\d+" s)))

3、筛选和判断一组数据中不为nil的

有这么一组数:

(def x '[(nil nil nil nil nil) (nil nil nil nil nil) ({:drug-id "300", :drug-name "西替利嗪,左西替利嗪(仙特朗,优泽)", :checked true, :dosage "1111", :dosage-unit "滴/天"} nil {:drug-id "302", :drug-name "谈说斯汀(UPDATE)", :checked true, :dosage "1111", :dosage-unit "滴/天"} nil) ()])

找出不为nil的

(filter (complement nil?) (mapcat identity x))

4、两个数中找到不为nil的第一个数

(first (filter (complement nil?)
        [a b]))

评论
  目录