如何优化Clojure代码:从多空格分隔文本列生成列表
优化Clojure列提取代码
输入数据
1 2 3 4 5 6 7 8 9 0
期望输出
((1 3 5 7 9) (2 4 6 8 0))
现有实现
(defn make-lists [] (let [lines (clojure.string/split-lines (slurp "input"))] (let [l1 (map #(parse-long (first (clojure.string/split % #" "))) lines) l2 (map #(parse-long (nth (clojure.string/split % #" ") 3)) lines)] (list l1 l2))))
存在的问题
- 对输入行进行了两次遍历,效率有优化空间
- 使用
#" "拆分多空格会产生大量空字符串,不得不硬编码nth 3来获取第二列,代码鲁棒性差,一旦空格数量变化就会出错
优化方案
方案一:利用转置特性一次处理
(defn make-lists [] (->> (slurp "input") clojure.string/split-lines (map #(->> (clojure.string/split % #"\s+") (map parse-long))) (apply map list)))
逻辑说明:
- 读取文件内容并按行拆分
- 对每一行用
#"\s+"(匹配一个或多个空白字符)拆分,避免空字符串问题,再将拆分后的字符串转为长整型 - 通过
apply map list将所有行的序列转置,直接得到以列为单位的两个列表,完全符合期望输出
方案二:用Reduce一次遍历收集
如果更倾向于显式的遍历收集,可以用reduce实现:
(defn make-lists [] (let [result (reduce (fn [[col1 col2] line] (let [[a b] (->> (clojure.string/split line #"\s+") (map parse-long))] [(conj col1 a) (conj col2 b)])) [() ()] (clojure.string/split-lines (slurp "input")))] (list (first result) (second result))))
逻辑说明:
- 初始化两个空列表作为累加器,分别对应两列
- 遍历每一行,拆分并转换为数字后,将两个数分别追加到对应列的列表中
- 最后将累加器中的两个列表转为目标格式的list
这两个方案都解决了原代码的两个问题:仅遍历一次输入行,同时适配任意数量的分隔空格,鲁棒性更强。
内容的提问来源于stack exchange,提问作者user1785730
相关产品推荐
相关产品推荐

