функция lisp для объединения списка строк
Мне нужно написать функцию, которая объединит список в строку. пример:
(concatString (цитата ("hello ""мир"))) = = > "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)))
)
)
)
)
Я получаю сообщение "Error:" hello" is and illegal Type specifier", когда я пытаюсь его запустить. Я пробовал множество способов изменить эту функцию, и я не смог понять это. у кого-нибудь есть идеи?
7 ответов
concatenate
требует спецификатор типа последовательности в качестве второго аргумента. Чтобы объединить две строки, вы должны вызвать concatenate
as:
(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))))))
просто используйте функцию format в списке, это преобразует все в строки и объединит их с правильной строкой формата.
(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)))
чтобы объединить последовательности в строку, используйте 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
минус один, a reduce
форма лучше:
(defun concat-strings (list)
(reduce (lambda (a b)
(concatenate 'string a b))
(remove-if-not #'stringp list)))
объединить тип результата & rest последовательности
Это должно работать
(concatenate 'string result item)
по словам Общая Поваренная Книга Lisp :
(concatenate 'string "Karl" " " "Marx")
"Karl Marx"
зачем ограничивать себя в списках?
(defun concatenate-strings (sequence)
(reduce #'(lambda (current next)
(if (stringp next)
(concatenate 'string current next)
current))
sequence
:initial-value ""))