Отфильтровывать любое значение, отличное от числа

#lisp #racket

#lisp #ракетка

Вопрос:

Я пытаюсь придумать процедуру, которая отфильтровывает любое значение, отличное от числа. Например:

'(1 2 (a) 3) => '(1 2 () 3) или '(1 2 (a 10 11 (b 2 (c))) 3) => '(1 2 (10 11 (2 ())) 3)

Это то, что у меня есть до сих пор, но на самом деле это не работает, потому что оно заменяет не числа пустым списком вместо ничего:

 (define (filter-numbers lst)
  (if (null? lst)
      '()
      (if (list? lst)
          (cons
           (filter-numbers (car lst))
           (filter-numbers (cdr lst)))
          (if (number? lst)
              lst
              '())))
  )
 

Процедура выводит следующее:

 > (filter-numbers '(1 2 (a) 3))
'(1 2 (()) 3)
 

вместо: '(1 2 () 3)

Ответ №1:

Вам нужно проверить, является ли элемент в подсписке числом, прежде чем принимать решение о cons его выводе или нет. Я думаю, будет проще, если мы немного реструктурируем код; также несколько советов: не используйте list? , предпочитайте pair? , так как это быстрее (в отличие list? от того, что не нужно проходить весь список). И предпочитайте cond вместо вложенности if s, ваш код будет легче читать. Вот что я имею в виду:

 (define (filter-numbers lst)
  (cond ((null? lst) lst)
        ((not (pair? (car lst)))
         ; check the element while still in a list, if we wait
         ; until we reach an atom it's too late to filter it out
         (if (number? (car lst))
             ; either add the element to the output or skip it
             (cons (car lst) (filter-numbers (cdr lst)))
             (filter-numbers (cdr lst))))
        (else (cons
               (filter-numbers (car lst))
               (filter-numbers (cdr lst))))))
 

Это работает так, как ожидалось:

 (filter-numbers '(1 2 (a) 3))
=> (1 2 () 3)
(filter-numbers '(1 2 (a 10 11 (b 2 (c))) 3))
=> '(1 2 (10 11 (2 ())) 3)
 

Комментарии:

1. Большое вам спасибо за вашу помощь! Это потрясающе 🙂