如何在Clojure中构建双键映射存储CSV温度数据并实现查询
Clojure CSV温度数据查询映射构建实现建议
需求说明
我需要编写程序读取CSV格式的温度数据表,实现按年份和日期查询对应温度集合的功能。CSV的格式规则为:
- 第一列:温度记录的年份
- 第二列:每月的具体日期
- 其余列:对应各月的温度值(示例:记录
2021-23-119表示2021年6月23日的温度为119)
目前已通过clojure.data.csv加载CSV数据并得到向量序列,计划构建以年份、日期为键,温度向量为值的嵌套映射来实现筛选查询,以下是具体实现建议。
已实现的CSV加载代码
(defn Load_csv_file [filepath] (try (with-open [reader (io/reader filepath)] (.skip reader 1) ( let [data (csv/read-csv reader)] (println data) ) ) (catch Exception ex (println (str "LOL Exception: " (.toString ex)))) ))
优化与实现步骤
1. 优化CSV加载逻辑
原代码中使用.skip reader 1跳过表头存在风险(不同编码下字符字节数不一致,可能导致内容截断),建议改为读取后通过drop 1跳过表头行,同时让函数返回解析后的数据集而非仅打印:
(require '[clojure.data.csv :as csv] '[clojure.java.io :as io]) (defn load-csv-file [filepath] (try (with-open [reader (io/reader filepath)] (->> (csv/read-csv reader) (drop 1) ; 安全跳过表头行 (map vec))) ; 将每行转换为向量,方便后续操作 (catch Exception ex (println (str "加载CSV异常: " (.toString ex))))))
2. 构建温度查询映射
通过reduce遍历所有数据行,构建外层键为年份、内层键为日期的嵌套映射,值为转换后的温度向量:
(defn build-temperature-map [csv-data] (reduce (fn [acc [year date & temps]] ;; 将温度字符串转换为数值类型(根据实际数据选择Integer/Double) (let [temp-vec (mapv #(try (Integer/parseInt %) (catch Exception _ nil)) temps)] (assoc-in acc [year date] temp-vec))) {} ; 初始空映射 csv-data))
- 若温度为浮点数,将
Integer/parseInt替换为Double/parseDouble - 加入
try-catch处理无效温度值,避免转换异常中断程序
3. 实现查询功能
编写简单的查询函数,通过get-in从嵌套映射中快速获取目标温度集合:
(defn query-temperature [temp-map year date] ;; 未找到对应记录时返回空向量 (get-in temp-map [year date] []))
4. 完整使用流程
(comment ;; 1. 加载CSV数据 (def temp-dataset (load-csv-file "your/temperature/data.csv")) ;; 2. 构建查询映射 (def temp-query-map (build-temperature-map temp-dataset)) ;; 3. 查询指定年份和日期的温度 (query-temperature temp-query-map "2021" "23") ; 返回对应温度向量 )
注意事项
- 键的类型:若CSV中年份/日期为数字格式,可将其转换为整数类型(如
(Integer/parseInt year))作为映射键,提升查询效率 - 数据清洗:若CSV中存在空值或无效数据,可在构建映射前先过滤或处理异常值
- 性能:
reduce为线性遍历,处理大数据量时仍保持高效
内容的提问来源于stack exchange,提问作者Ebel Ofori
相关产品推荐
相关产品推荐

