2

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?

1
  • 3
    The way in your Edit looks good to me. Commented Aug 22, 2012 at 10:04

3 Answers 3

6

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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)))

1 Comment

The problem isn't so much laziness. But that calling toString on a LazySeq of characters doesn't return a string consisting of the characters in that seq. The OP would have a similar problem with a vector of characters or a list of characters.
1
(str/join " " (map (fn [f col] (f col))
               [first last]
               (map #(str/split % #" ") [a b])))

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.