How can I convert a LazySeq of Characters to a String in Clojure?
Solution 1:
This works:
(apply str my-char-seq)
Basically, str calls toString() on each of its args and then concatenates them. Here we are using apply to pass the characters in the sequence as args to str.
Solution 2:
Another way is to use clojure.string/join
, as follows:
(require '[clojure.string :as str] )
(assert (= (vec "abcd") [\a \b \c \d] ))
(assert (= (str/join (vec "abcd")) "abcd" ))
(assert (= (apply str (vec "abcd")) "abcd" ))
There is an alternate form of clojure.string/join
which accepts a separator. See:
http://clojuredocs.org/clojure_core/clojure.string/join
For more complicated problems, you may also wish to lookat strcat
from the Tupelo library:
(require '[tupelo.core :as t] )
(prn (t/strcat "I " [ \h \a nil \v [\e \space (byte-array [97])
[ nil 32 "complicated" (Math/pow 2 5) '( "str" nil "ing") ]]] ))
;=> "I have a complicated string"
Solution 3:
As a special case, if the underlying type of the sequence in question is clojure.lang.StringSeq
you can also do:
(.s (my-seq))
which is extremely performant as it is just pulling out the public final CharSequence field from the clojure StringSeq class.
Example:
(type (seq "foo"))
=> clojure.lang.StringSeq
(.s (seq "foo"))
=> "foo"
(type (.s (seq "foo")))
=> java.lang.String
an example of the timing implications (and note the difference when using a type hint):
(time
(let [q (seq "xxxxxxxxxxxxxxxxxxxx")]
(dotimes [_ 1000000]
(apply str q))))
"Elapsed time: 620.943971 msecs"
=> nil
(time
(let [q (seq "xxxxxxxxxxxxxxxxxxxx")]
(dotimes [_ 1000000]
(.s q))))
"Elapsed time: 1232.119319 msecs"
=> nil
(time
(let [^StringSeq q (seq "xxxxxxxxxxxxxxxxxxxx")]
(dotimes [_ 1000000]
(.s q))))
"Elapsed time: 3.339613 msecs"
=> nil