【问题标题】:How to work around cdr not understanding the empty list?如何解决 cdr 不了解空列表?
【发布时间】:2017-05-03 09:48:10
【问题描述】:

我的问题是butSecondLastAtom 算法。它不起作用,因为 cdr 不理解空列表。但是我看不到其他编写算法的方法。它在页面的末尾。一切正常,但当列表的最后一个元素是列表时。 http://lpaste.net/110959

问题在于 (cdr (cdr l)) 的递归调用,但更多的是在第 3 个条件中。不知道该怎么办。我今晚要停下来,早上重新开始。

((and (isAtom (second_last_element l)) (notAtom (last_element l)))
        (cons
           (car l)
             (butSecondLastAtom (last_element l))))

【问题讨论】:

标签: scheme


【解决方案1】:

我认为您代码中的主要问题是在flattenbutLast 的列表的cdr 上使用null?cdr。不要这样做;始终使用列表本身的过程和谓词。

我建议如下:

扁平化列表

大多数方案都有一个 flatten 内置版本,它负责嵌套列表不正确的列表。你实现的版本不完全正确(试试(flatten '())),用这个:

(define (flatten lst)
  (let loop ((lst lst) (res null))
    (cond 
      ((null? lst) res)
      ((pair? lst) (loop (car lst) (loop (cdr lst) res)))
      (else        (cons lst res)))))

> (flatten '(1 2 (3 (4 5 6))))
'(1 2 3 4 5 6)
> (flatten '(1 2 (3 (4 5 (6)))))
'(1 2 3 4 5 6)
> (flatten '())
'()

删除倒数第二个元素

所以现在这变得容易多了,循环遍历一个简单的平面正确列表,同时跟踪最后一个 (n-1) 和倒数第二个 (n-2) 元素。一个示例实现是:

(define (butSecondLastAtom lst)
  (define flst (flatten lst))
  (if (< (length flst) 2)
      flst
      (let loop ((flst (cddr flst)) (n-2 (car flst)) (n-1 (cadr flst)) (res null))
        (if (null? flst)
            (reverse (cons n-1 res)) ; here we drop the second-last element
            (loop (cdr flst) n-1 (car flst) (cons n-2 res))))))

如果您想避免遍历列表两次(一次用于length,一次用于循环),您还可以自己跟踪长度:

(define (butSecondLastAtom lst)
  (define flst (flatten lst))
  (let loop ((lst flst) (len 0) (n-2 #f) (n-1 #f) (res null))
    (if (null? lst)
        (if (< len 2)
            flst
            (reverse (cons n-1 res))) ; here we drop the second-last element
        (loop (cdr lst) (add1 len) n-1 (car lst) (if (< len 2) null (cons n-2 res))))))

测试

> (butSecondLastAtom '(1 2 (3 (4 5 6))))
'(1 2 3 4 6)
> (butSecondLastAtom '(1 2 (3 (4 5 (6)))))
'(1 2 3 4 6)
> (butSecondLastAtom '(((a))))
'(a)
> (butSecondLastAtom '())
'()

【讨论】:

  • 过早优化。上次我计时时发现使用length 甚至可能比不遍历列表两次要快一些。
  • @Sylwester 这也是我的感觉,但我没有测量任何东西。我还发现第一个版本更优雅。但是有时不可避免地有人会提出这个问题,所以就在那里;-)
猜你喜欢
  • 1970-01-01
  • 2014-06-17
  • 1970-01-01
  • 2022-10-06
  • 2023-01-24
  • 2011-11-21
  • 2021-12-24
  • 2011-11-25
  • 1970-01-01
相关资源
最近更新 更多