Today’s a palindrome – how to check palindromes in Clojure

There’re countries like Poland that use dates in the format ‘dd.mm.YYYY’, so today’s 21.02.2012. As pointed by @KevlinHenney on twitter it’s a palindrome and I was pleasantly surprised to find it out.

I came up with the idea of writing a Clojure function to check if a given string is a palindrome.

I remember the moment very well when I stumbled upon the (conj) function and learnt that it behaves slightly different when executed with a list or an array.

user=> ;; use conj with a list (mind the quote mark)
user=> (conj '(1 2 3) 0)
(0 1 2 3)
user=> ;; use conj with an array
user=> (conj [1 2 3] 0)
[1 2 3 0]

I think that in order to fully embrace the concept of functional programming is to use the three functions: map, reduce and filter extensively, and so I insisted on using them to tackle the problem.

Here’s the function I developed to check whether a given string is a palindrome or not.

user=> (defn my-reverse [s]
         (let [lst (list)]
           (reduce #(str %2 %1)
                   (mapcat #(conj lst %1) s))))
#'user/my-reverse

user=> (defn palindrome? [s]
         (= s (my-reverse s)))

user=> (is (palindrome? "21022012"))
true

I solved the problem, but with mapcat not map. Is there a way to use just the three functions – map, reduce and filter?

Be Sociable, Share!
This entry was posted in Languages.

10 Responses to Today’s a palindrome – how to check palindromes in Clojure

  1. Mark Engelberg says:

    (defn is-palindrome? [s] (= (seq s) (reduce conj () s)))

  2. Andrew says:

    Hi Jacek,

    Minor nitpick: square brackets denote a vector literal in Clojure and are different to arrays (which are java mutable arrays).

    You’re string reverse function is a lot more complicated than it needs to be. Here

    (let [lst (list)] … #(conj lst %1) …)

    is a long way of saying

    list

    ; Note that

    ()

    is also a literal for the empty list in Clojure. However, mapping list over a sequence and then concatenating the result is an identity operation on the sequence. You could just call

    seq

    on

    s

    . Lastly, because you are passing s to a seq consuming function anyway, you can elide the call to

    seq

    yourself.

    This simplifies

    my-reverse

    down to:

    (defn str-reverse [s] (reduce #(str %2 %) "" s)

    An alternate formulation that takes advantage of lists building from the front might be

    (defn str-reverse [s] (apply str (reduce conj () s)))

    I think that in order to fully embrace the concept of functional programming is to use the three functions: map, reduce and filter extensively, and so I insisted on using them to tackle the problem.

    Another fun variation of this is to use

    juxt

    ,

    partial

    and

    comp

    :

    (def palindrome? (comp (partial apply =) (juxt seq (partial reduce conj ()))))
  3. Craig Andera says:

    Strings are associative by index. So you could do something like (map (partial nth s) (range (dec (count s)) -1 -1)) to reverse the string.

  4. Norman Richards says:

    In addition to what the prior poster says, I’d note a few more things.

    – [let lst (list)] strikes be as being particularly non-idiomatic. I’d use () instead.

    – (mapcat #(conj lst %1) s) is particularly redundant. If you want to force a seq, use (seq s). If you really need to force the issue for educational reasons, perhaps (map identity s) ?

    – Of course s is a seq, so you could simplify your reduce to (reduce #(str %2 %1) s)

    – Another reduce option: (reduce str (into () s) But, of course there’s no map here.

  5. Si Yu says:

    how about (defn palindromes [s] (= s (apply str (reverse s))))

  6. Manuel says:

    My solution:

    (defn palindrome? [word] (if (= word (apply str (reverse word))) true false))

    If you want to use this function with numbers too, you only need to wrap word with the str function:

    (defn palindrome? [word] (let [strword (str word)] (if (= strword (apply str (reverse strword))) true false)))

  7. Pingback: Today’s a palindrome redux – a slimmer version of palindrome? function with reduce | Japila :: verba docent, exempla trahunt

  8. Piotr T. says:

    How about #(= (reverse %) (-> % reverse reverse)) ?

  9. Jan says:

    #(= (reverse %) (vec %))

Leave a Reply

%d bloggers like this: