There's also re-split in str-utils in clojure.contrib;

(use 'clojure.contrib.str-utils)
(re-split #"\s" "The quick brown fox")
=> ("The" "quick" "brown" "fox")

You can then use all the good clojure collection functions;

(def words (re-split #"\s" "The quick brown fox"))
(some #{"brown"} words)
=> "brown"
(some #{"foo"} words)
=> nil
(nth words 2)
=> "brown"
(str-join "," words)
=> "The,quick,brown,fox"
..., etc.

(There's also some good stuff in str-utils2 worth looking at).

The "some" function above needs some explanation;
It takes a predicate, applies it to each element of the collection and
returns the first logical true (not nil) value if found otherwise nil.
The #{"brown"} is a set containing "brown", but sets, like maps are a
function of their elements, e.g;
(#{"a" "b"} "b")
=> "b"
and hence acts as a predicate for testing each element in words in the
some function.

There are also endless things you can do with map and reduce;

(map (fn [w] (.toUpperCase w)) words)
=> ("THE" "QUICK" "BROWN" "FOX")
same as;
(map #(.toUpperCase %) words)
=> ("THE" "QUICK" "BROWN" "FOX")

Say you wanted to encode a "record" of stems from a map of word/stem's;

(let [stems {"the" :th "quick" :qk "brown" :br "fox" :fx}]
  (reduce (fn [rec x] (conj rec (stems (.toLowerCase x)))) [] words))
=> [:th :qk :br :fx]

So then given that background and that you're looking for a clojure
approach rather than a specific solution to your "brown" split
example, lets elaborate on a possible approach;

You could "abstract" the requirement to something like;
"Given a collection and a predicate to find an element in that
collection, return two collections - up to the split element and the
remaining elements (including the split element)."

(defn split-coll
"Doc as above."
[coll pred]
(reduce (fn [[l r] x]
   (if-not (empty? r) [l (conj r x)]
      (if (pred x) [l [x]] [(conj l x) r]))) [[][]] coll))

(split-coll '(:a :b :c) #(= % :b))
=> [:a] [:b :c]]
(split-coll '(:a :b :c) #(= % :x))
=> [[:a :b :c] []]
(split-coll '(:a :b :c) #(= % :a))
=> [[] [:a :b :c]]

and of course;
(split-coll words #(= % "brown"))
=> [["The" "quick"] ["brown" "fox"]]

finally, you could create the specific sentence function;

(defn split-sentence [sentence word] (split-coll (re-split #"\s"
sentence) #{word}))
(split-sentence "The quick brown fox" "brown")
=> [["The" "quick"] ["brown" "fox"]]

and you can also use de-structuring to get exactly what you were
originally looking for;
(let [[l r] (split-sentence "The quick brown fox" "brown")] r)
=> ["brown" "fox"]

To explain the above reduce function ; we start with two empty vectors
in a vector [[][]] and then looping through the collection on each
iteration that vector is passed to the fn as the first arg. We
de-structure that into l and r for the left and right vectors. If r is
not empty we've already found the element, so conj x into the r
vector. Otherwise if x satisfies the pred, conj it to the r vector,
else we haven't got there yet, so conj it to the l vector.

For completeness, I should show a loop/recur alternative as this is a
totally idiomatic clojure technique, but should be used for functional
goals, not just trying to emulate imperative ways.

(defn split-coll
[coll pred]
(loop [c coll [l r] [[][]]]
  (if (nil? (seq c)) [l r]
  (recur (next c) (let [x (first c)]
           (if (nil? c) [l r] (if-not (empty? r) [l (conj r x)] (if
(pred x) [l [x]] [(conj l x) r]))))))))

(split-coll words #(= % "brown"))
=> [["The" "quick"] ["brown" "fox"]]

It is also important to master loop/recur as you can use this more
easily than reduce for complex looping constructs, nested loops,
performant techniques, etc.

I hope that gives you a feel of the kinds of things you can do with
functional idioms and clojure and also a general approach to
functional programming. Takes a while to pickup all these tips but
you'll never look back.

Rgds, Adrian.

--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to