функция lisp для объединения списка строк - PullRequest
10 голосов
/ 28 марта 2011

Мне нужно написать функцию, которая объединит список в строку.пример:(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)))          
        )
      )
  )
)

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

Ответы [ 7 ]

16 голосов
/ 28 марта 2011

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))))))
16 голосов
/ 28 марта 2011

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

(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)))
7 голосов
/ 28 марта 2011

Чтобы объединить последовательности в строку, используйте 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)))
3 голосов
/ 28 марта 2011

Согласно Common Lisp Cookbook :

(concatenate 'string "Karl" " " "Marx")
"Karl Marx"
3 голосов
/ 28 марта 2011

Common Lisp the Language, 2-е издание

объединить тип результата и отдых последовательности

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

(concatenate 'string result item)
2 голосов
/ 29 сентября 2015

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

(defmacro concatString (& остальные строки) `(объединенная строка, @ строки))

2 голосов
/ 28 марта 2011

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

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