2016-02-13 3 views
1

Я хочу найти все атомы из дерева, расположенные на заданном уровне k. Я пытался что-то вроде:Lisp: список узлов на заданном уровне k

(defun atoms (l) 
    ;returns the list of atoms of l at its superficial level 
    (cond 
    ((null l) l) 
    ((or (atom l) (numberp l)) l) 
    ((or (atom (car l)) (numberp (car l))) 
     (append (list(car l)) (atom (cdr l)))) 
    (T (atoms (Cdr l))))) 

(defun findat (l pos k) 
    (cond 
    ((null l) l) 
    ((= k pos) (atoms l)) 
    ((and (or (atom l) (numberp l)) (= k pos)) l) 
    (T (cons '() (mapcar #'(lambda (l) (findat l (+ pos 1) k)) l))))) 

так, для образца: л = (а (Ь (г)) (с (д (е)) (е))), поз = 0 и к = 2, я должен получить результат: (gdf), но вместо этого, я получаю некоторую ошибку, говоря, что «A не имеет тип LIST». Кто-нибудь знает, как исправить мой код? Заранее спасибо!

+0

(1) Это еще один вопрос, когда вы говорите о «нелинейном списке». Я знаю [линейные/нелинейные структуры данных] (https://en.wikipedia.org/wiki/List_of_data_structures#Linear_data_structures), но я редко сталкиваюсь с нелинейными списками: это термин, используемый учителем или учебником? Я думаю, что вы зададите вопрос, если бы вы сказали «дерево». (2) Пожалуйста, правильно отпечатайте свой код (3) 'defun' четко идентифицирует ваш код как« common-lisp », обновите теги (4). Почему вы пишете« мой код »жирным шрифтом, как в вашем другом вопросе? Как вы узнаете об альтернативных (возможно, лучших) подходах? – coredump

+0

Я использую термин «нелинейный», потому что так говорит мой учитель. С этого момента я попытаюсь использовать «дерево». Кроме того, вы правы в отношении проблемы «моего кода». , Я хочу сначала исправить свой код, и, конечно, я открыт для любых других решений. Спасибо за советы. – Nelly

+0

'(или (atom x) (numberp x))' содержит избыточность. Все числа являются атомами Нет никакого способа, чтобы '(atom x)' мог терпеть неудачу, но '(numberp x)' success. – Kaz

ответ

3

Вот несколько измененная версия вашего findat. Возможно, вам захочется подумать о более лучшем имени для функции (по крайней мере, выписать ее полностью (find-atoms) вместо того, чтобы аббревиатура излишне).

(defun findat (l k) 
    "Find atoms on level K in list L." 
    (cond 
    ((atom l) '()) 
    ((= k 0) (remove-if (complement #'atom) l)) 
    (t (mapcan #'(lambda (l) 
        (findat l (1- k))) 
       l)))) 

(findat '(a (b (g)) (c (d (e)) (f))) 2) 
; => (G D F) 

Изменения:

  • Я удалил аргумент pos. Легче просто пересчитать k.
  • Я изменил первый случай, чтобы проверить наличие атомов (включая nil). Он возвращает пустой список, чтобы append в последнем случае отменил его. Фактически возвращение желаемых атомов обрабатывается вторым случаем.
  • Я использовал стандарт remove-if вместо вашего atoms. Вызов complement создает предикат, который соответствует любому, что не является атомом. Таким образом, remove-if содержит только атомы. Вы также можете использовать remove-if-not и оставить complement, но это устарело.
  • В последнем случае я использовал (reduce #'append ...) для создания плоского списка атомов. Редактировать: Изменено для использования mapcan.

Обратите внимание также, как я положил строку в начале функции. Это докшрин. Вы должны сделать это вместо того, чтобы оставлять комментарий там, как в вашем atoms. Таким образом вы можете использовать (describe #'findat), чтобы увидеть документацию (или вы можете использовать Emacs/IDE для ее просмотра).

+0

'(уменьшить # 'append (mapcar ...))' может сокращенно как «mapcan» – coredump

+0

@ coredump- О, хорошо, я не думал об этом. – jkiiski

+0

@ jkiiski Спасибо, это действительно помогло мне. – Nelly

Смежные вопросы