\"hello world\"" />
开发者

lisp function to concatenate a list of strings

开发者 https://www.devze.com 2023-02-20 00:56 出处:网络
I need to write a function that will concatenate a list into a string. example: (concatString (quote (\"hello\" \" world\"))) ==> \"hello world\"

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?


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


Just use the format function on a list, this will convert everything to strings and concatenate them with the correct format string.

(defun my-concat( list )
  (format nil "~{~a~}" list))

If you want to concatenate them with a space use this form with the "~^" directive:

(defun my-concat( list )
  (format nil "~{~a~^ ~}" list))

If you'd like to filter out the results, you can just transform the list before formatting it.

(defun my-concat(list)
  (format nil "~{~a~^ ~}" (remove-if-not #'stringp list)))


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


Common Lisp the Language, 2nd Edition

concatenate result-type &rest sequences

This one should work

(concatenate 'string result item)


According to the Common Lisp Cookbook :

(concatenate 'string "Karl" " " "Marx")
"Karl Marx"


Why limit yourself to lists?

(defun concatenate-strings (sequence)
  (reduce #'(lambda (current next)
              (if (stringp next)
                (concatenate 'string current next)
                current))
          sequence
          :initial-value ""))


Here are my two cents:

(defmacro concatString (&rest strings) `(concatenate 'string ,@strings) )

0

精彩评论

暂无评论...
验证码 换一张
取 消