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) `(конкатенация строки), @строки))