Возврат списка без последнего элемента - PullRequest
0 голосов
/ 26 февраля 2019

Я только начал изучать ракетку.

У меня есть этот код:

#lang racket

(define l1 '(1 2 3 4))
(car l1)
(cdr l1)

(car l1) возвращает 1.(cdr l1) возвращает '(2 3 4)

Есть ли функция, которая возвращает '(1 2 3)?

Я пробовал это:

#lang racket

(define l1 '(1 2 3 4))
(map
 (lambda (l i)
   (if (not (= i (sub1 (length l1)))) l '()))
 l1 (range 0 (length l1)))

Но, этовозвращает: '(1 2 3 ())

И я также пытался:

#lang racket

(define l1 '(1 2 3 4))
(map
 (lambda (l i)
   (cond ((not (= i (sub1 (length l1)))) l )))
 l1 (range 0 (length l1)))

Но он возвращает: '(1 2 3 #<void>)

Ответы [ 7 ]

0 голосов
/ 26 февраля 2019

Вот еще один, через zip:

#lang racket

(require srfi/1)

(define (but-last-zip xs)
  (if (null xs)
      xs                      ; or error, you choose
      (map (lambda (x y) x)
           xs
           (cdr xs))))

Вот еще один, эмулирующий фильтрацию через списки с добавлением, где пустые списки исчезают сами по себе:

(define (but-last-app xs)
  (if (null? xs)
      xs
      (let ((n (length xs)))
        (apply append                  ; the magic
               (map (lambda (x i)
                      (if (= i (- n 1)) '() (list x)))
                    xs
                    (range n))))))

Или мы могли бы использоватьукрашать - фильтровать - декорировать напрямую, это еще больше кода!

(define (but-last-fil xs)
  (if (null? xs)
      xs
      (let ((n (length xs)))
        (map car
             (filter (lambda (x) (not (null? x)))
                     (map (lambda (x i)
                            (if (= i (- n 1)) '() (list x)))
                          xs
                          (range n)))))))
0 голосов
/ 26 февраля 2019

Вот эквивалент Уилса Несса прекрасного but-last-zip, который не полагается на srfi/1 в Racket: без srfi/1 Racket's map настаивает на том, что все его аргументы имеют одинаковую длину (так какделает версию R5RS на самом деле), но в других Лиспах это обычное явление для завершения функции в конце кратчайшего списка.

Эта функция использует for/list Ракетта, а также подключаетпредположение, что результатом для пустого списка является пустой список.

#lang racket

(define (but-last-zip xs)
  (for/list ([x xs] [y (if (null? xs) xs (rest xs))])
    x))

Я думаю, что версия Уилла чище: мне кажется, что отображение функций на вещи - очень полезная вещь, в то время как for/list чувствует себя меньшеЛиспи мне.Единственное преимущество этой версии в том, что она не требует модуля.

0 голосов
/ 26 февраля 2019

Мое собственное решение с использованием рекурсии:

#lang racket

(define but-last
  (lambda (l)
    (cond ((null? (cdr l)) '())
          (else (cons (car l) (but-last (cdr l)))))))

И еще одно решение с использованием filter-not и map:

#lang racket

(define l1 '(1 2 3 4))

(filter-not empty? (map
 (lambda (l i)
   (if (not (= i (sub1 (length l1)))) l empty))
 l1 (range 0 (length l1))))
0 голосов
/ 26 февраля 2019

Вот еще один вариант, предполагая, что список не пуст.Он эффективен (он выполняет один проход по списку), и он не становится проще, чем этот!

(define (delete-last lst)
  (drop-right lst 1))

(delete-last '(1 2 3 4))
=> '(1 2 3)
0 голосов
/ 26 февраля 2019

length - это, как правило, антишаблон в схеме, поскольку для получения результата необходимо прочитать весь список.У. Несс отмечает, что map не меняет структуру списка, а поведение filter основано на значениях списка , ни то, ни другое не соответствует вашим потребностям.

Вместо того, чтобы сначала делать потенциально дорогостоящие вычисления или неловко применять библиотечные функции, вы можете вычислить init списка с использованием прямой рекурсии -

(define (init l)
  (cond ((null? l)
         (error 'init "cannot get init of empty list"))
        ((null? (cdr l))
         null)
        (else
         (cons (car l)
               (init (cdr l))))))

(init '(a b c d e)) ;; '(a b c d)
(init '(a))         ;; '(a)
(init '())          ;; init: cannot get init of empty list

Или хвосто-рекурсивной формы, котораяиспользуется только один reverse -

(define (init l)
  (let loop ((acc null)
             (l l))
    (cond ((null? l)
           (error 'init "cannot get init of empty list"))
          ((null? (cdr l))
           (reverse acc))
          (else
           (loop (cons (car l) acc)
                 (cdr l))))))

(init '(a b c d e)) ;; '(a b c d)
(init '(a))         ;; '(a)
(init '())          ;; init: cannot get init of empty list

И, наконец, хвостово-рекурсивная форма, которая не использует length или reverse.Для получения дополнительной информации о том, как это работает, см. «Как работают функции коллектора в схеме?» -

(define (init l (return identity))
  (cond ((null? l)
         (error 'init "cannot get init of empty list"))
        ((null? (cdr l))
         (return null))
        (else
         (init (cdr l)
               (lambda (r)
                 (return (cons (car l) r)))))))

(init '(a b c d e)) ;; '(a b c d)
(init '(a))         ;; '(a)
(init '())          ;; init: cannot get init of empty list
0 голосов
/ 26 февраля 2019

Функция map всегда возвращает список той же длины, что и его входные данные.Вы хотите, чтобы выходной список был короче, чем его ввод.Функция, которую вы ищете, традиционно называется but-last:

(define (but-last xs) (reverse (cdr (reverse xs))))
0 голосов
/ 26 февраля 2019

А как насчет этого?

(define (myCdr l)
    (if (not (pair? (cdr l)))
        '()
        (cons (car l) (myCdr (cdr l)))
    )
)
...