I know your question was a technical one rather than a question about
Clojure coding, but your solution led me to wonder about a number of
Clojure coding points.
My solution to the palindrome detector also needed to calculate the
size of half the list. New Clojurians quickly discover that the "/"
function returns ratio results (not necessarily whole numbers). I see
you used Java to call Math.floor to get your integer. At first, I
used a cast: (int (/ (count list))). Then I found the whole-number
functions for dividing: "quot" (quotient) and "rem" (remainder).
Your overall design includes building a list of booleans which are
tested to see if they're all true. I'm wondering if there's something
in Clojure that's a little more concise than #(= true %) to see if
something is true. I don't see a "true?" predicate. I wonder if the
fact that we're looking for one means "we're doing it wrong"?
My last point of wondering relates to performance. I'm still wrapping
my head around the basics of Clojure, so I'm not yet totally sure how
to mentally judge what's going on behind the scenes (or what -may- go
on, depending on the type of collections passed in to these functions)
with respect to performance.
My solution was to calculate the size of half of the collection, then
just compare the equality of the first half of the list with the
reverse of the last half of the list.
#(let [n (quot (count %) 2)]
(= (take n %) (reverse (take-last n %))))
I think this is nicely expressed and readable, but for all I know it
might be terrible performance-wise.
I'm curious if anyone can give a quick explanation of the big-O
behaviors of both of these solutions. I'd like to be able to get more
natural insight on how to think about what's happening (or again, what
-may- happen depending on collection type) behind the scenes.
My original strategy involved a loop/recur where each iteration
compared the 1st and last element of the list, then "and" that with a
recursive call on a new list with the 1st and last elements removed.
But I worried that this would potentially yield unfavorable O(n^2)
performance, since popping-off the last element of a list (as in a
Clojure linked list) would be an O(n) operation on each iteration
However, I don't know if I didn't just sweep some O(n^2) operations
under the rug with my "readable" solution above.
If anyone has a hint on a technique/approach that yields better big-O
performance, let me know!