Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reverse a string (simple question)

Tags:

Is there a better way to do this in Clojure?

daniel=> (reverse "Hello")
(\o \l \l \e \H)

daniel=> (apply str (vec (reverse "Hello")))
"olleH"

Do you have to do the apply $ str $ vec bit every time you want to reverse a string back to its original form?

like image 977
djhworld Avatar asked Sep 19 '11 10:09

djhworld


People also ask

How do you reverse a string interview question?

add each character to the front of the accumulator. This actually reverses the string . lets say your string is 'ab', you take the first character which is 'a' and make it your accumulator. now the add the second char 'b' to the front of the accumulator such that you will get 'ba', a reversed string.

What does it mean to reverse a string?

In programming, a string is a sequence of characters. It is one of the basic data types that we use to express text rather than numbers. Reversing a string means flipping the order of the characters completely. In other words, we are making the string read backwards.

What is the logic of string reverse?

Reversing a string is the technique that reverses or changes the order of a given string so that the last character of the string becomes the first character of the string and so on. Furthermore, we can also check the Palindrome of the given string by reversing the original string.


Video Answer


2 Answers

You'd better use clojure.string/reverse:

user=> (require '[clojure.string :as s])
nil
user=> (s/reverse "Hello")
"olleH"

UPDATE: for the curious, here follow the source code snippets for clojure.string/reverse in both Clojure (v1.4) and ClojureScript

; clojure:
(defn ^String reverse
  "Returns s with its characters reversed."
  {:added "1.2"}
  [^CharSequence s]
  (.toString (.reverse (StringBuilder. s))))

; clojurescript
(defn reverse
  "Returns s with its characters reversed."
  [s]
  (.. s (split "") (reverse) (join "")))
like image 160
skuro Avatar answered Oct 13 '22 23:10

skuro


OK, so it would be easy to roll your own function with apply inside, or use a dedicated version of reverse that works better (but only) at strings. The main things to think about here though, is the arity (amount and type of parameters) of the str function, and the fact that reverse works on a collection.

(doc reverse)

clojure.core/reverse
([coll])
Returns a seq of the items in coll in reverse order. Not lazy.

This means that reverse not only works on strings, but also on all other collections. However, because reverse expects a collection as parameter, it treats a string as a collection of characters

(reverse "Hello")

and returns one as well

(\o \l \l \e \H)

Now if we just substitute the functions for the collection, you can spot the difference:

(str '(\o \l \l \e \H) )
"(\\o \\l \\l \\e \\H)"

while

(str \o \l \l \e \H )
"olleH"

The big difference between the two is the amount of parameters. In the first example, str takes one parameter, a collection of 5 characters. In the second, str takes 5 parameters: 5 characters.

What does the str function expect ?

(doc str)
-------------------------
clojure.core/str
([] [x] [x & ys])
  With no args, returns the empty string. With one arg x, returns
  x.toString().  (str nil) returns the empty string. With more than
  one arg, returns the concatenation of the str values of the args.

So when you give in one parameter (a collection), all str returns is a toString of the collection. But to get the result you want, you need to feed the 5 characters as separate parameters to str, instead of the collection itself. Apply is the function that is used to 'get inside' the collection and make that happen.

(apply str '(\o \l \l \e \H) )
"olleH"

Functions that handle multiple separate parameters are often seen in Clojure, so it's good to realise when and why you need to use apply. The other side to realize is, why did the writer of the str function made it accept multiple parameters instead of a collection ? Usually, there's a pretty good reason. What's the prevalent use case for the str function ? Not concatenating a collection of separate characters surely, but concatenating values, strings and function results.

(let [a 1 b 2]
  (str a "+" b "=" (+ a b)))
"1+2=3"

What if we had a str that accepted a single collection as parameter ?

(defn str2
  [seq]
  (apply str seq)
  )

(str2 (reverse "Hello"))
"olleH"

Cool, it works ! But now:

(let [a 1 b 2]
  (str2 '(a "+" b "=" (+ a b)))
  )
"a+b=(+ a b)"

Hmmm, now how to solve that ? :)

In this case, making str accept multiple parameters that are evaluated before the str function is executed gives str the easiest syntax. Whenever you need to use str on a collection, apply is a simple way to convert a collection to separate parameters.

Making a str that accepts a collection and have it evaluate each part inside would take more effort, help out only in less common use cases, result in more complicated code or syntax, or limit it's applicability. So there might be a better way to reverse strings, but reverse, apply and str are best at what they do.

like image 40
12 revs Avatar answered Oct 13 '22 22:10

12 revs