Question

I have several strings:

(def a "some random string")
(def b "this is a text")

Now i want to concatenate parts of them to create a string "some text". Unfortunately both of the strings below didn't work.

(clojure.string/join " " [(take 4 a) (take-last 4 b)])
(str (take 4 a) " " (take-last 4 b))

It's because functions take and take-last return lazy sequences. The question is: what is the proper way to concatenate multiple lazy sequences of strings and return one string?

Edit: I found one solution - (apply str (concat (take 4 a) " " (take-last 4 a))) - but is it the most correct way?

Was it helpful?

Solution

Rather than using sequence functions to slice the input strings, you might want to use the much more efficient subs (for substring; note there's a GC-related caveat about it, see below):

(subs "asdf" 1 2)
; => "s"

;; a and b as in the question text
(clojure.string/join " " [(subs a 0 4) (subs b (- (count b) 4))])
; => "some text"

The aforementioned caveat is that as long as the "s" returned in the first example here remains ineligible for garbage collection, so does the original "asdf" (since subs returns a "view" onto the input String without allocating fresh storage -- this is the behaviour of Java's substring method which subs wraps). This is not a problem if you immediately hand the "s" off to subs and retain no other reference to it, since join will discard it after pulling the characters.

If you do end up working with lazy sequences of characters after all, there's nothing to be done but to use something like (map (partial apply str) [...your vector here...]) to turn the inputs to clojure.string/join into strings.

OTHER TIPS

Try this, and yes becoz of the laziness the result of your code is not proper.

(str (apply str (take 4 a)) " " (apply str (take-last 4 b)))
(str/join " " (map (fn [f col] (f col))
               [first last]
               (map #(str/split % #" ") [a b])))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top