如何让Clojure的loadData函数返回指定格式的文件记录列表?
问题修正与说明
原函数的问题点
doseq不返回集合:doseq是用于执行副作用的迭代工具,执行完毕后默认返回nil,无法生成并返回处理后的记录集合。- 正则转义错误:分割符
#"\\|"多了一层转义,Clojure中只需用#"\|"即可匹配竖线。 - 结果结构不符合预期:原代码将ID和剩余数据放在嵌套向量中,会得到
[1 ["Xxx" "info1" "222-2222"]]的结构,不是需要的扁平格式。
修正后的代码
(ns your-app.core (:require [clojure.java.io :as io] [clojure.string :as str])) (defn load-data [filename] (with-open [rdr (io/reader filename)] (->> (line-seq rdr) (map #(str/split % #"\|")) (map #(map str/trim %)) ; 可选:去除字段前后的空格(适配文件行尾空格) (map (fn [[id & rest-fields]] (cons (Integer/parseInt id) rest-fields))) (map vec) doall)))
代码解释
- 用
->>线程宏串联操作,逻辑更清晰。 line-seq生成每行的惰性序列,str/split按竖线分割每行字段。str/trim处理字段前后的空格(比如文件行尾的空格),根据实际情况可省略。- 把每个记录的第一个字段转成整数,和剩余字段合并成扁平序列,再转成向量(需要列表的话用
list替代vec)。 doall强制惰性序列求值,因为with-open会在代码块结束后关闭阅读器,不提前求值后续无法访问数据。
如何使用返回的列表
调用函数加载数据后,可通过绑定变量进行各种操作:
;; 加载文件数据 (def records (load-data "path/to/your/file.txt")) ;; 遍历打印所有记录 (doseq [rec records] (println rec)) ;; 根据ID查找指定记录 (defn find-by-id [records target-id] (first (filter #(= target-id (first %)) records))) (println (find-by-id records 2)) ; 输出: [2 "Yyy" "info2" "333-3333"] ;; 提取所有ID (def all-ids (map first records)) (println all-ids) ; 输出: (1 2 3) ;; 提取所有联系电话 (def all-phones (map last records)) (println all-phones) ; 输出: ("222-2222" "333-3333" "444-4444")
内容的提问来源于stack exchange,提问作者EL_
相关产品推荐
相关产品推荐

