Lisp функция для объединения списка строк

Мне нужно написать функцию, которая объединит список в строку. Пример:

  (concatString (quote ( "hello" "world" ))) == > "hello world"

вот что я до сих пор:

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

Я получаю сообщение об ошибке "Ошибка:" привет и недействительный тип ", когда я пытаюсь запустить его. Я пробовал кучу способов изменить эту функцию, и я не мог понять это. есть ли у кого-нибудь идеи?

Ответ 1

concatenate требуется спецификатор типа последовательности в качестве второго аргумента. Чтобы объединить две строки, вы должны называть concatenate следующим образом:

(concatenate 'string "hello" "world")

Еще одна ошибка в вашем коде: вы не убедитесь, что car списка - это строка перед назначением result. Исправив ваш код, я придумал следующую реализацию:

(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"

Следующее переопределение concatString более эффективно, так как оно не создает много объектов промежуточной строки:

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

Ответ 2

Просто используйте функцию формата в списке, это преобразует все в строки и объединит их с правильной строкой формата.

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

Если вы хотите объединить их с пространством, используйте эту форму с директивой "~ ^":

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

Если вы хотите отфильтровать результаты, вы можете просто преобразовать список перед его форматированием.

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

Ответ 3

Чтобы объединить последовательности в строку, используйте concatenate 'string.

(defun concat-strings (list)
  (apply #'concatenate 'string list))

Чтобы удалить что-либо из списка, который не является строкой, используйте remove-if-not.

(defun concat-strings (list)
  (apply #'concatenate 'string
         (remove-if-not #'stringp list)))

Если аргумент не является списком, сообщение об ошибке будет сообщено remove-if-not. Вы можете добавить это утверждение прежде, чем, конечно, дать более конкретное сообщение об ошибке, но оно действительно не добавляет значения здесь.

(defun concat-strings (list)
  (assert (listp list)
          "This is not a list: ~s." list)
  (apply #'concatenate 'string
         (remove-if-not #'stringp list)))

EDIT:

Как отмечает Райнер, apply работает только в списках ограниченной длины. Если у вас нет оснований полагать, что ваш список не может быть длиннее call-arguments-limit минус один, форма reduce лучше:

(defun concat-strings (list)
  (reduce (lambda (a b)
            (concatenate 'string a b))
          (remove-if-not #'stringp list)))

Ответ 4

Общий Lisp Язык, 2-е издание

конкатенировать результат-тип & rest Последовательности

Это должно работать

(concatenate 'string result item)

Ответ 5

В соответствии с Common Lisp Cookbook:

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

Ответ 6

Зачем ограничивать себя списками?

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

Ответ 7

Вот мои два цента:

(defmacro concatString (& rest strings) `(конкатенация строки), @строки))