Найдите самый вложенный список внутри списка в Common Lisp

Я новичок в общем Lisp и функциональном программировании, но у меня много опыта в таких языках, как C, C++, C#, Java и так далее. У меня проблемы с поиском самого вложенного списка внутри списка. Мое мнение-это что-то вроде этого:

(0 1 (2 3) 4 (5 (6 (7) 8)) 9)

Я хотел бы получить самый вложенный список внутри этого списка, который в этом случае является

(7)

у меня была идея, что я могу как-то сгладить список, пока не останется только один под-список. Чтобы проиллюстрировать, что я имею в виду, вот несколько шагов:

Шаг 1. - ввод:

(0 1 (2 3) 4 (5 (6 (7) 8)) 9)

Шаг 2. - сгладить на "первом уровне":

(0 1 2 3 4 5 (6 (7) 8) 9)

Шаг 3. - сгладить на "втором уровне":

(0 1 2 3 4 5 6 (7) 8 9)

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

у меня возникли проблемы с реализацией этой процедуры в Common Lisp, поэтому я бы благодарен за некоторые указатели в правильном направлении, может быть, какой-то пример кода и так далее. Это домашнее задание, поэтому я не ожидаю полного решения, но был бы рад, если бы кто-то указал, возможно, более простое и лучшее решение и его реализацию.

3 ответов


вот мое (не очень чистое) решение в CL:

(defun deepest-list (lst)
  (let ((max-depth 0) ret)
    (labels ((inner-deepest-lst (lst depth)
           (cond
         ((null lst) depth)
         ((listp (car lst))
          (let ((local-max (max
                    (inner-deepest-lst (first lst) (1+ depth))
                    (inner-deepest-lst (rest lst)  (1+ depth)))))
            (and (> local-max max-depth) (setf ret (first lst) max-depth local-max))
            local-max))
         (t (inner-deepest-lst (rest lst) depth)))))
      (inner-deepest-lst lst 1))
    ret))

edit:

после Второй мысли, это немного более чистое решение:

(defun deepest-list (lst)
  (labels ((dl (lst depth)
         (cond
           ((atom lst) (cons 0 lst))
           ((every #'atom lst) (cons depth lst))
           (t (funcall (lambda (x y) (if (> (car x) (car y)) x y))
               (dl (car lst) (1+ depth))
               (dl (cdr lst) depth))))))
    (rest (dl lst 0))))

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

Я написал его в схеме, которая, вероятно, не будет сразу переведена на Common Lisp, поэтому я не чувствую, что это будет полной отдачей. Тем не менее, он может быть испорчен, поэтому будьте осторожны.

(define (deepest lst)
  (let ((filtered (filter pair? lst)))
    (cond ((null? filtered) lst)
          (else (deepest (concatenate filtered))))))

ваш подход итеративного выравнивания список, вероятно, должны работать нормально, хотя это не самый эффективный или (субъективно) элегантный способ сделать это.

Если есть более одного такого списка, правильный вывод будет зависеть от спецификации - должны ли вы вернуть все из них, или только первый, или бросить ошибку?

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