0

I have a random amount of strings in a seq that I'm trying to "destructure"? into separate strings, while also dropping the last string in the seq.

("a" "b" "c") -> "a" "b"

I tried a few things, and the closest I've got is with (apply str (drop-last args)), but as you probably know, this turns the seq of strings into a single string.. "ab"

How do I do this?

3
  • You can not have multiple strings out in the blue. Using drop-last will give you a seq with the last element missing, but it's still a seq you can hold on to -- and you need some container to hold on to. Maybe add more information what your ultimate goal is? Commented Nov 7, 2020 at 17:57
  • @cfrick I'm trying to pass a variable amount of strings as arguments to a function. Commented Nov 7, 2020 at 18:12
  • 1
    I think you may be looking for apply? Simply put, it allows you to use a seq as arguments to a function. Commented Nov 7, 2020 at 20:53

1 Answer 1

1

It sounds like you'd use sequential destructuring:

(def col-of-strings '("a" "b" "c" "d" "e"))

(let [ [a b c & etc ]  col-of-strings
       last            (drop-last etc) ]
  (println "a=" a " b=" b " c=" c " and etc=" etc " last=" last))

which prints

a= a  b= b  c= c  and etc= (d e)  last= (d)

Another option would be to remove the last string first, then destructure:

(let [ col-minus-last  (drop-last col-of-strings)
              [ a b c & etc]  col-minus-last ]
  (println "a=" a " b=" b " c=" c " etc=" etc))

which prints

a= a  b= b  c= c  etc= (d)

If you really don't know how many elements are in your collection then I think your best bet may be to use a loop:

(loop [ c  (drop-last col-of-strings) ]
  (let [s  (first c) ]
    (println "s=" s)
    (if (nil? s)
      nil
      (recur (rest c)))))

EDIT

OP says he wants to pass a variable number of strings for processing. In that case it sounds like recursively walking down the list would be appropriate:

(defn vararg-func [ s & etc]
  (println "s=" s)
  (if (nil? s)
    nil
    (recur (first etc) (rest etc))))

But since OP says he already has a lazy sequence of strings (filenames) I think the easiest way to handle it is to simply pass the sequence into the function and loop over it:

(defn seq-func [ s ]
  (loop [ str     (first s)
          usw     (rest s) ]
    (println "str=" str)
    (if (nil? str)
      nil
      (recur (first usw) (rest usw)))))

which is very similar to the earlier code.

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

3 Comments

Great answers. Thank you.
I just got to looking at vararg-func and realized I'd messed it up, because the function entry is always a recurrence point - so I didn't need the explicit loop. Similarly, I re-did seq-func to recur to the head of the function instead of an internal loop point. Sometimes I get kind of stuck in my thinking - I guess it's time for more electro-shock treatments! :-)
seq-fn could be (defn seq-fn [[x & xs :as data]] (when (seq data) (println "x =" x) (recur xs))) , while vararg-fn (defn vararg-fn [& args] (loop [[x & xs :as data] args] (when (seq data) (println "x =" x) (recur xs))))

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.