On Mon, May 30, 2011 at 11:29 PM, Alan Malloy <a...@malloys.org> wrote: > (filter identity (map f xs)) is more clearly written as (keep f xs), > unless you're relying on the former to retain false (not nil) elements.
Eh -- filter identity doesn't retain false: => (filter identity [false nil 42 "foo" []]) (42 "foo" []) On the other hand, keep does. So it looks like you got that backward. When the elements are all characters extracted from a string, though, it's moot since neither false nor nil will appear in the input seq. Furthermore, the OP asked for implementation in terms of the basic HOFs, of which map is a particularly common one. Additionally, in many cases filtering on another object, such as an explicit sentinel, would be necessary and keep would be useless; and in still more cases there may be no filtering needed at all, if there's something in the output for every input. Lastly, filter, identity, and map are all quite familiar and common compared to keep. One situation not discussed yet in this thread is the case where one may wish to append a varying amount of material to a sequence on each iteration, beyond just zero items or one to sometimes two or more. In that case: * The loop version needs (into bui [some elements]) * So do the reduce and iterate versions. * The for version would need to produce seqable values and be wrapped in (apply concat ...). * The map version becomes mapcat and produces seqable values. * The explicit lazy-seq version can also use into, but it looks a little strange because the recursive call comes *before* the step-generated elements. These can be demonstrated on the OP's problem, though, using empty or one-element vectors in composing the result: (defn rem-dup [stri] (loop [[x y & z] (seq stri) ,bui []] (if x (recur (cons y z) (into bui (if (= x y \space) [] [x]))) bui))) (defn rem-dup-iter [stri] (first (first (drop-while (comp nil? first) (iterate (fn [[_ [x y & z] bui]] (if x [nil (cons y z) (into bui (if (= x y \space) [] [x]))] [bui nil nil])) [nil (seq stri) []]))))) (defn rem-dup-mapcat [stri] (let [stri (seq (concat stri [(char 0)]))] (mapcat (fn [x y] (if (= x y \space) [] [x])) stri (next stri)))) (defn rem-dup-for [stri] (apply concat (for [[x y] (partition 2 1 [] stri)] (if (= x y \space) [] [x])))) (defn rem-dup-reduce [stri] (reduce (fn [bui [x y]] (into bui (if (= x y \space) [] [x]))) [] (partition 2 1 [] stri))) (defn rem-dup-lazy-seq [stri] (lazy-seq (let [[x y & z] stri] (if x (into (rem-dup-lazy-seq (cons y z)) (if (= x y \space) [] [x])))))) All of the above versions can be generalized to add arbitrary subseqs on each iteration, conditionally. Every one of them has an (if ... [] [x]) clause somewhere. If you change the [] in that clause to, say, "XX", it will replace every space in a run of spaces except the last with a pair of Xs: (defn rem-dup-mapcat-xs [stri] (let [stri (seq (concat stri [(char 0)]))] (mapcat (fn [x y] (if (= x y \space) "XX" [x])) stri (next stri)))) => (rem-dup-mapcat-xs "aaaa bb cc") (\a \a \a \a \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \X \space \b \b \space \c \c) => (count (filter #{\X} (rem-dup-mapcat-xs "aaaa bb cc"))) 34 Note that there are 18 spaces between the "a"s and the "b"s in the input, and the output has 34 \X characters followed by a space there -- the 17 spaces before the last were each replaced with a pair of \X characters. -- Protege: What is this seething mass of parentheses?! Master: Your father's Lisp REPL. This is the language of a true hacker. Not as clumsy or random as C++; a language for a more civilized age. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en