Join multiple lazy sequences of strings in Clojure
-
27-06-2021 - |
문제
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?
해결책
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.
다른 팁
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])))