I need to write a function that will concatenate a list into a string. example:
(concatString (quote ("hello" " world"))) ==> "hello world"
here is what i have so far:
(defun concatString (list)
"A non-recursive function that concatenates a list of strings."
(cond
((not (listp list))
(princ "Error: argument to concatNR must be a list")(terpri) ())) ; check if parameter is a list
(if (not (null list)) ;check if list is not null
(let ((result (car list)))
(dolist (item (cdr list))
(if (stringp item)
(setq result (concatenate result item)))
)
)
)
)
I'm getting a "Error: "hello" is and illegal type specifier" message when i try to run it. I've tried a bunch of ways to modify this function and i havent been able to figure it out. does anyone have any ideas?
To concatenate sequences to a string, use concatenate 'string
.
(defun concat-strings (list)
(apply #'concatenate 'string list))
To remove anything from the list that is not a string, use remove-if-not
.
(defun concat-strings (list)
(apply #'concatenate 'string
(remove-if-not #'stringp list)))
If the argument is not a list, an error will be signaled by remove-if-not
. You can add the assertion before, of course, to give a more specific error message, but it does not really add value here.
(defun concat-strings (list)
(assert (listp list)
"This is not a list: ~s." list)
(apply #'concatenate 'string
(remove-if-not #'stringp list)))
EDIT:
As Rainer notes, apply
only works on lists of limited length. If you do not have reason to believe that your list cannot be longer than call-arguments-limit
minus one, a reduce
form is better:
(defun concat-strings (list)
(reduce (lambda (a b)
(concatenate 'string a b))
(remove-if-not #'stringp list)))
concatenate
requires a sequence type specifier as its second argument. To concatenate two strings, you should call concatenate
as:
(concatenate 'string "hello" "world")
Another bug in your code: you do not make sure that the car
of the list is a string before assigning it to result
. By fixing your code, I came up with the following implementation:
(defun concatString (list)
"A non-recursive function that concatenates a list of strings."
(if (listp list)
(let ((result ""))
(dolist (item list)
(if (stringp item)
(setq result (concatenate 'string result item))))
result)))
;; tests
> (concatString (list "hello" " world"))
"hello world"
> (concatString (list "hello" 1 2 3 " world"))
"hello world"
> (concatString (list "hello" 1 2 "3" " world"))
"hello3 world"
> (concatString (list 1 2 3 "hello" " world"))
"hello world"
The following redefinition of concatString
is more efficient as it does not create many intermediary string objects:
(defun concatString (list)
"A non-recursive function that concatenates a list of strings."
(if (listp list)
(with-output-to-string (s)
(dolist (item list)
(if (stringp item)
(format s "~a" item))))))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With