3

The task is to write a function that reverses a sequence. I am trying to do this as efficiently and clojure-ish as possible, but I can't figure out the best way. It doesn't feel right to create a variable and start appending items to that variable. What would seem idiomatic to me was if there was a way to do the following:

From the Clojure docs

(map-indexed (fn [idx itm] [idx itm]) "foobar")
--> ([0 \f] [1 \o] [2 \o] [3 \b] [4 \a] [5 \r])

What I have done is this:

(defn testing [x]
(map-indexed (fn [idx itm] [(- (count x) idx) itm]) x))

Which yields:

(testing "foobar")
--> ([6 \f] [5 \o] [4 \o] [3 \b] [2 \a] [1 \r])

What I can't figure out is how to essentially pack that back up into a new list with the correct indexes. Honestly, even the concept of declaring a variable is escaping me in Clojure at the moment. All my experience is with Python and Ruby.

2
  • 1
    You can find the source code of reverse at clojuredocs.org/clojure_core/clojure.core/reverse#source. Commented Apr 14, 2014 at 20:29
  • 1
    Can I suggest that you re-title the question "Implement reversing a sequence in a way that is idiomatic for Clojure". The idiomatic way to return a sequence in general is usually lazily, but that isn't the case for this problem. Commented Apr 15, 2014 at 12:36

2 Answers 2

4

Strings are sequable so we can use clojure.core/reduce

(defn rev [x]
  (reduce #(str %2 %1) x))

(rev "foobar") ;; "raboof"

The idea is that for each iteration, we create a new string that is the next character in the sequence prepended to the current string.

All my experience is with Python and Ruby

Here is the same in Ruby:

def rev(x)
  x.chars.reduce { |s, c| c + s }
end

For non-strings

(defn rev [x]
  (reduce conj () x))

(rev [1 2 3 4 5]) ;; (5 4 3 2 1)
Sign up to request clarification or add additional context in comments.

4 Comments

Excellent. Thanks much! I knew this was one of those things that would be simple even though I was over here banging my head against the wall.
Actually @Kyle , for some reason I'm having an equal amount of trouble making this work with a seq that isn't a string. Any thoughts?
@Borromakot I added a solution for non-strings. If you were to use this with a string you may want to (apply str (rev "foobar")) to get a string as output.
Thanks! Great stuff. I was looking in the entirely wrong place. I had assumed that I was just trying to connect the two, using concat or conj or something along those lines. Didn't even know about cons. Thanks again!
1

You can reverse a sequence using indexes, as your question proposes, as follows:

(defn reverse [s]
  (let [v (vec s)] (map v (range (dec (count v)) -1 -1))))

... or, perversely,

(def reverse (comp rseq vec))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.