在Clojure中有更好的方法吗?

时间:2013-07-09 13:54:10

标签: clojure functional-programming

我有这个函数来读取文件并将其转换为两元素列表的列表:

(def f1 "/usr/example")

(defn read-file [file]
  (let [f
        (with-open [rdr (clojure.java.io/reader file)]
          (doall (map list (line-seq rdr))))]
    (cond 
      (= file f1) (map #(map read-string (split (first %) #" ")) f)
      :else (map #(map read-string (split (first %) #"\t")) f))))

我正确使用condsplit文件(我有两种类型的文件,第一种用空格分隔元素,第二种用制表符分隔)。

第一种类型的文件如下:

"1.3880896237218878E9 0.4758112837388654
1.3889631620596328E9 0.491845185928218"

而第二个是:

'1.3880896237218878E9\t0.4758112837388654
1.3889631620596328E9\t0.491845185928218"

我得到了我想要的结果,例如:

((1.3880896237218878E9 0.4758112837388654) (1.3889631620596328E9 0.491845185928218))

但是我想知道是否有更简洁的方法可以做到这一点,可能使用较少的map函数或在没有cond的情况下执行此操作

1 个答案:

答案 0 :(得分:4)

返回向量向量,在任意空格上分割单独的行,并使用Double/parseDouble读取单个双精度数。它没有处理的是文件中的任何单引号或双引号字符;如果它们是实际输入的一部分,我想我只是用正则表达式对它进行预处理以摆脱它们(见下文)。

(require '[clojure.java.io :as io] '[clojure.string :as string])

(defn read-file [f]
  (with-open [rdr (io/reader f)]
    (mapv (fn [line]
            (mapv #(Double/parseDouble %) (string/split line #"\s+")))
          (line-seq rdr))))

对于上述预处理,您可以使用#(string/replace % #"['\"]" "")删除所有单引号。如果它们出现在输入的开头和结尾,或者可能是单独的行,那将是合适的。 (如果引用了单个数字,那么您需要确保不删除它们之间的所有分隔符 - 在这种情况下,最好用单个空格替换然后使用string/trim删除任何分隔符字符串末尾的空格。)