【问题标题】:Return a list without the last element返回没有最后一个元素的列表
【发布时间】:2023-04-02 05:20:01
【问题描述】:

我刚刚开始学习球拍。

我有这个代码:

#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>)

【问题讨论】:

  • 你可以使用reverse吗?
  • @WillNess 是的,我想是的。但我想让它移植到 Scheme(如果可能的话)。
  • 试试吧。 :) 你能得到 reversed “butlast” 元素吗? (这就是你想要的函数在普通的 lisp 中被称为,顺便说一句 - “butlast”)。
  • 我正在尝试做类似(filter not empty? (map (lambda (l i) ... 的事情,但它不起作用。而且,我正在尝试使用递归而不使用map。
  • 但是如果你刚开始学习 Lisp,那么自己用直接递归来编写代码是一个很好的练习,即使用 if, null?缺点,汽车,cdr 和递归,来感受一下。你应该首先喜欢自己编写这样的小函数,然后厌倦自己编写它们,然后转而使用库函数。

标签: list functional-programming scheme lisp racket


【解决方案1】:

这样的事情怎么样?

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

【讨论】:

  • 我已经编辑了我的答案。它现在应该可以工作了。感谢 Will Ness 的想法 :)
  • 不客气。只需为它选择一个更好的名称。 :)
【解决方案2】:

map 函数总是返回一个与其输入长度相同的列表。您需要一个比其输入短的输出列表。您要查找的函数传统上称为but-last:

(define (but-last xs) (reverse (cdr (reverse xs))))

【讨论】:

    【解决方案3】:

    length 在 Scheme 中通常是一种反模式,因为需要读取整个列表才能得到结果。 W. Ness 指出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。有关其工作原理的更多直觉,请参阅"How do collector functions work in Scheme?" -

    (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
    

    【讨论】:

    • ... 如果我们使用 (x -> [x | p x]) 并测试是否为 null,那么过滤器 可以 在结构上使用?在里面。仍然,它太复杂了。 :)
    • 有人写了"a Haskell programmer's factorial function",太搞笑了。这个也开始看起来像这样的候选人。 :)
    【解决方案4】:

    这里还有另一种选择,假设列表非空。它很高效(它对列表执行一次遍历),而且没有比这更简单的了!

    (define (delete-last lst)
      (drop-right lst 1))
    
    (delete-last '(1 2 3 4))
    => '(1 2 3)
    

    【讨论】:

    • 如果只有 take 允许负数...(Haskell 可以,khm,khm...)
    • @WillNess 啊哈!但在球拍中,我们有drop-right。我忘记了!
    • 你在空列表上试过了吗?.... ukhm,很好的保存,要求它是非空的。 :)
    【解决方案5】:

    我自己使用递归的解决方案:

    #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))))
    

    【讨论】:

    • 请注意,您的 but-last 函数不是一个完整的函数:如果应用于空列表,它将引发错误。第二种解决方案的行为不同:如果应用于空列表,它将返回一个空列表。
    • 好的,这个是结构的。虽然,太复杂了。 :) -- 哦,不,我收回了。 '(1 () 2) 的结果是什么??
    • 顺便说一句,最后一个的复杂度是多少?你能说,它是线性的吗?
    • 在循环中调用length,我什至没有看到那个 waaaaa :(
    • 请不要批评,而是告诉我如何解决您评论的所有错误。
    【解决方案6】:

    这里还有一个,通过压缩:

    #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))))))
    

    或者我们可以直接使用decorate--filter--undecorate,代码更多!

    (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)))))))
    

    【讨论】:

    • but-last-zip 很漂亮:我想到了使用 map 和它的一个参数来缩短一个列表,然后愚蠢地坚持廉价地制作这样一个列表(就像我说的,愚蠢地)。烦人的是,由于烦人的球拍烦躁,它在球拍中不起作用,但for/list 可以:至少它应该一直很烦躁。
    • 它适用于(require srfi/1)。如果你有一个 Rackety 版本,带有 for/list 等,这将是这个意想不到的庞大条目的一个很好的补充。 :) :) :)
    【解决方案7】:

    这里是 Will Ness's beautiful but-last-zip 的等价物,它不依赖于 Racket 中的 srfi/1:没有 srfi/1 Racket 的 map 坚持认为它的所有参数都是相同的长度(事实上 R5RS 版本也是如此)但在其他 Lisps 中,函数在最短列表的末尾终止是很常见的。

    这个函数使用 Racket 的 for/list 并且还假设空列表的结果是空列表。

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

    我认为 Will 的版本更纯粹:我认为在事物上映射函数是非常 Lisp 的事情,而 for/list 对我来说不那么 Lisp。这个版本的唯一优点是它不需要模块。

    【讨论】:

    • 它是更多的球拍。 for 构造绝对是 Racket-y,这是我的印象。
    • 是的,我同意:我认为从某种意义上说,“更多的 Rackety”就是“更少的 Lispy”。当然,两者都不一定更好。
    猜你喜欢
    • 1970-01-01
    • 2016-01-30
    • 2013-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-12
    • 2017-03-03
    • 2017-05-11
    相关资源
    最近更新 更多