Clisp: выбрать подсписки с заданной длиной - PullRequest
0 голосов
/ 28 июня 2018

Работа над CLISP в Sublime Text.

Exp. в CLISP: менее 1 года

Я уже некоторое время пытаюсь решить это упражнение ... безуспешно ... как вы можете догадаться.

Фактически мне нужно создать функцию, которая будет изменять список и хранить только те списки, которые равны или превышают заданное число (см. Ниже)

Список, над которым я должен работать:

(setq liste '((a b) c (d) (e f) (e g x) f))

Я должен найти это как результат:

(lenght 2 liste) => ((a b) (e f) (e g x))
liste => ((a b) (e f) (e g x))

Вот мой код:

(defun lenght(number liste)
    (cond
        ((atom liste) nil)
        ((listp (car liste))
            (rplacd liste (lenght number (cdr liste))) )
        ((<= (lenght number (car liste)) number)
         (I don't know what to write) )
        ((lenght number (cdr liste))) ) )

Будет очень любезно, если вы дадите мне лишь небольшую подсказку, чтобы я мог найти хороший результат.

Спасибо, ребята.

Ответы [ 3 ]

0 голосов
/ 28 июня 2018

Ну, я нашел ответ, который искал, почесав голову до крови ...

Серьезно, вот решение, которое работает (и спасибо за исправление длины, которое помогло мне найти решение ^^):

(defun filter-by-min-length (min-length liste)
    (cond
        ((atom liste) nil)
        ((and (listp (car liste))(>= (length (car liste)) min-length))
            (rplacd liste (filter-by-min-length min-length (cdr liste))) )
        ((filter-by-min-length min-length (cdr liste))) ) )
0 голосов
/ 29 июня 2018

Немодифицирующая версия

(defun filter-by-min-length (min-length le)
  (cond ((atom le) nil)
        ((and (listp (car le)) (>= (length (car le)) min-length))
         (cons (car le) (filter-by-min-length min-length (cdr le))))
        (t (filter-by-min-length min-length (cdr le)))))

Тест:

(defparameter *liste* '((a b) c (d) (e f) (e g x) f))
(filter-by-min-length 2 *liste*)
;; ((A B) (E F) (E G X))
*liste*
;; ((A B) C (D) (E F) (E G X) F)  ; -> *liste* not modified

Для формирования хороших привычек я бы рекомендовал использовать defparameter вместо setq, поскольку поведение setq не всегда может быть определено (см. здесь ). В ссылке сказано:

используйте defvar, defparameter или let для ввода новых переменных. Используйте setf и setq чтобы изменить существующие переменные. Используя их, чтобы представить новое Переменные не определены поведение

0 голосов
/ 28 июня 2018

Изменение списка не имеет особого смысла, потому что оно становится волосатым во главе списка, чтобы сохранить исходную ссылку. Вернуть новый список.

Это операция фильтрации. Обычный оператор в Common Lisp для этого - remove-if-not (или remove-if, или remove, в зависимости от условия). Требуется предикат, который должен возвращать, должен ли элемент быть сохранен. В этом случае, кажется, (lambda (element) (and (listp element) (>= (length element) minlength))).

(defun filter-by-min-length (minlength list)
  (remove-if-not (lambda (element)
                   (and (listp element)
                        (>= (length element) minlength)))
                 list))

Во многих случаях, когда условие известно во время компиляции, loop производит более быстрый скомпилированный код:

(defun filter-by-min-length (minlength list)
  (loop :for element :in list
        :when (and (listp element)
                   (>= (length element) minlength))
          :collect element))

Возвращает новый список, который удовлетворяет условию. Вы бы назвали это как (let ((minlength-list (filter-by-min-length 2 raw-list))) …).

Многие базовые курсы вначале настаивают на рекурсивном использовании примитивных операций над консолями в учебных целях.

Первая попытка обычно игнорирует возможное исчерпание стека. На каждом шаге вы сначала смотрите, находитесь ли вы в конце (затем возвращаете ноль), должен ли первый элемент быть отброшен (затем возвращать результат повторения для остальных), или если он должен быть сохранен (затем с результат рекурсии).

Если доступна оптимизация хвостового вызова, вы можете изменить ее, чтобы использовать аккумулятор. На каждом шаге вместо того, чтобы сначала возвращать, а затем обрабатывать, вы сохраняете сохраненное значение в аккумуляторе и передаете его в рекурсию. В конце вы не вернете ноль, а поменяете местами аккумулятор и вернете его.

...