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?

akond
  • 15,865
  • 4
  • 35
  • 55
J. Doe
  • 35
  • 1
  • 7
  • 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? – cfrick Nov 07 '20 at 17:57
  • @cfrick I'm trying to pass a variable amount of strings as arguments to a function. – J. Doe Nov 07 '20 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. – Shlomi Nov 07 '20 at 20:53

1 Answers1

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.

  • Great answers. Thank you. – J. Doe Nov 07 '20 at 18:36
  • 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! :-) – Bob Jarvis - Слава Україні Nov 07 '20 at 18:45
  • 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))))` – leetwinski Nov 08 '20 at 09:03