Как перевернуть список — схему

#list #scheme #racket

#Список #схема #рэкет

Вопрос:

 (define (oddrev ls)
    (cond ((null? ls) ls)
          ((null? (cdr ls)) ls)
          (else (cons (car ls) (oddrev (cdr (cdr ls)))))))
 

У меня есть схема, которая возвращает нечетные элементы массива, но я хочу перевернуть список в конце.
Как бы я это сделал??

Ответ №1:

Тривиальным решением является добавление уровня косвенности:

 (define (oddrev-helper ls)
    (cond ((null? ls) ls)
          ((null? (cdr ls)) ls)
          (else (cons (car ls) (oddrev-helper (cdr (cdr ls)))))))

(define (oddrev ls) (reverse (oddrev-helper ls)))
 

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

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

Вы можете воспользоваться этим, если вам действительно нужен обратный результат.

 (define (oddrev-helper ls acc)
  (cond ((null? ls) acc)
        ((null? (cdr ls)) (cons (car ls) acc))
        (else (oddrev-helper (cdr (cdr ls)) (cons (car ls) acc)))))

(define (oddrev ls) (oddrev-helper ls '()))
 

Ответ №2:

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

 (define (oddrev ls (acc '()))
    (cond ((or (null? ls) (null? (cdr ls))) acc)
          (else (oddrev (cdr (cdr ls)) (cons (car ls) acc)))))
 

Или стандартными функциями более высокого порядка:

 (define (oddrev ls)
  (reverse (filter odd? ls)))
 

Попробуйте:

 (oddrev '(1 2 3 4 5 6))
;; '(5 3 1)
 

измените строку

 (cond ((or (null? ls) (null? (cdr ls))) acc)
 

Для:

 (cond ((or (null? ls) (null? (cdr ls))) (reverse acc))
 

чтобы он возвращался в порядке ввода: '(1 3 5)