I originally wrote this as an answer to a question on Stack Overflow, but it turned out so nicely that I decided to post it here to see if I can make it even better.
(defn char-seq "Returns a lazy sequence of characters from rdr. rdr must implement java.io.Reader." [rdr] (let [c (.read rdr)] (if-not (neg? c) (cons (char c) (lazy-seq (char-seq rdr)))))) (defn line-offsets "Returns a lazy sequence of offsets of all lines in s." [s] (if (seq s) (->> (partition-all 3 1 s) (map-indexed (fn [i [a b c]] (cond (= b \newline) (if c (+ 2 i)) (= a \return) (if b (inc i))))) (filter identity) (cons 0)))) (defn ordered-line-seq "Returns the lines of text from raf at each offset in offsets as a lazy sequence of strings. raf must implement java.io.RandomAccessFile." [raf offsets] (map (fn [i] (.seek raf i) (.readLine raf)) offsets))
(let [filename "data.txt" offsets (with-open [rdr (clojure.java.io/reader filename)] (shuffle (line-offsets (char-seq rdr))))] (with-open [raf (java.io.RandomAccessFile. filename "r")] (run! println (ordered-line-seq raf offsets))))
I'm interested in any way to improve this code, but here are some specific things I'm looking for:
RandomAccessFileobviously uses byte offsets, and
line-offsetsreturns character offsets, this code won't work for Unicode files. Is there a way to fix that problem without adding a lot of complexity?
cgood names for the parameters of the anonymous function in
- What exactly are the guidelines for parameter ordering in named functions like