"3,4,5,6,7,8,9"

and return the same except containing only the numbers that are perfect squares, which in this case would be

"4,9"

So the first step is to break up that string into the individual numbers. In the Clojure String library we get the

**split**function, which takes your string and a regular expression that determines what part of the string is to be used to split. We're using just about the simplest possible option, just chopping through the commas. A function to do this would look so:

(defn split-string [s]

(clojure.string/split s #","))

This gives us a sequence of the separated strings:-

user=> (split-string "4,5,45,6,7,67")

["4" "5" "45" "6" "7" "67"]

When we want to join these back again to restore the single string we have split's partner

**join**, so:-

(defn join-string [ss]

(clojure.string/join "," ss))

We just specify the string "," to be added between the strings in our sequence.

user=> (join-string ["4" "5" "45" "6" "7" "67"])

"4,5,45,6,7,67"

Now we will want to get the integer values of these strings. So we dip into the Java class

**Integer**and bring back the method

**parseInt**. I love it when you can step between languages and they play nicely together. In the system I use professionally I can step from C to assembler and back again. It's similar in that Clojure has Java hiding inside and C has assembler hiding inside. Anyway to change a string to an integer I can summon the Integer class and call the parseInt method on it, like this:-

user=> (. Integer parseInt "123")

123

That's a macro but it can become a function quite easily:-

user=> (#(. Integer parseInt %) "123")

123

And we will want to convert these integers back into strings: the Clojure function

**str**will do this:-

user=> (str 3)

"3"

We will want a filter function that will decide whether a number is a square. For this let's dip into Java again and get the square root method from the Math class:-

user=> (. Math sqrt 2.0)

1.4142135623730951

So if I take the integer part of the square root (the Clojure function

**int**will give this) and square this and compare with the original number that indicates whether it is was a square number. Along these lines:-

(defn is-square [n]

(let [root (int (. Math sqrt n))]

(= (* root root) n)))

user=> (is-square 100)

true

user=> (is-square 101)

false

user=> (is-square 99)

false

OK so putting the parts together. The first version of my function just-squares will open up the string into the individual numbers and then put them together again:-

(def just-squares

(fn [s]

(join-string (split-string s))))

user=> (def s "4,5,6,7,8,9")

#'user/s

user=> (just-squares s)

"4,5,6,7,8,9"

So far so good. Now convert them to integers and back again.

(def just-squares

(fn [s]

(join-string

(map str

(map #(. Integer parseInt %) (split-string s))))))

user=> (just-squares s)

"4,5,6,7,8,9"

Still works. Now add that filter to allow only the square ones:-

(def just-squares

(fn [s]

(join-string

(map str

(filter (fn [n] (let [root (int (. Math sqrt n))](= (* root root) n)))

(map #(. Integer parseInt %) (split-string s)))))))

user=> (just-squares s)

"4,9"

Ok so this works. Now to make this code complete in itself I should fill in the definitions of those functions split-string and join-string, so we get this:-

(def just-squares

(fn [s]

(#(clojure.string/join "," %)

(map str

(filter (fn [n] (let [root (int (. Math sqrt n))](= (* root root) n)))

(map #(. Integer parseInt %) (clojure.string/split s #",")))))))

Hmm. Well, that works on the 4Clojure page but I don't like it. Maybe there's scope to use the

**->**macro to link the sections together instead of nesting them. Or use more

**lets**to give the sections some names.

Also a more idiomatic name for

**is-square**would have been

**square?**.

## No comments:

## Post a Comment