删除最后一个ATOM

时间:2014-09-13 20:13:18

标签: list functional-programming scheme

我想从给定列表中删除最后一个ATOM -

(define (butSecondLastAtom lst1)
 (cond 
   ((null? lst1) '())
   ((null? (cdr lst1)) lst1)
   ((null? (cddr lst1))
   (cond((not(pair? (car lst1))) (cdr lst1))
     (else (cons(butLastAtom (car lst1)) (cdr lst1)))))
(else (cons (car lst1) (butSecondLastAtom(cdr lst1))))))

(define (butLastAtom x)
    (cond ((null? (cdr x))
      (cond ((not(pair? (car x))) '())
           (else (cons (butLastAtom(car x)) '()))))
    (else (cons (car x) (butLastAtom(cdr x))))))

此代码会删除第二个最后一个原子,但对以下条件失败 - 如果输入像(a(b(c(d)))那么输出应该导致(a(b((d))))。 请更新我错在的地方或解决方案。

2 个答案:

答案 0 :(得分:2)

以下是我对问题的理解,但由于您只提供一个测试用例,请确保这是您想要的。

该解决方案有2次通过:

传递1 - 计算原子数

相当古典,计算我们有多少原子,以便我们可以计算出哪一个原子可以放弃:

(define (count-atoms sexp)
  (cond
    ((null? sexp) 0)
    ((pair? sexp) (+ (count-atoms (car sexp)) (count-atoms (cdr sexp))))
    (else 1)))

传递2 - 没有第二个

的副本

首先,我需要一个atom?谓词:

(define (atom? x) 
  (not (or (pair? x) (null? x))))

在没有删除任何元素的情况下复制与上一个函数非常相似:

(define (copy sexp)
  (cond
    ((or (null? sexp) (atom? sexp)) sexp)
    (else (cons (copy (car sexp)) (copy (cdr sexp))))))

为了删除元素,我们需要更改第二个子句,并引入一个计数器,以便我们知道何时遇到要删除的元素:

(define (butSecondLastAtom sexp)
  (define n 1)                       ; counter of atoms
  (define ignore (count-atoms sexp)) ; index of element to ignore
  (define (sub sexp)                 ; the copy subroutine
    (cond
      ((null? sexp) null)
      ((atom? sexp)
       (set! n (add1 n))               ; increase n
       sexp)
      (else 
       (let* ((left   (sub (car sexp))) ; process car of cons cell
              (leftn  n)                ; keep track of n after processing car
              (right  (sub (cdr sexp))) ; process cdr of cons cell
              (rightn n))              ; keep track of n after processing cdr
         (cond
           ((and (atom? left)  (= leftn  ignore)) right)
           ((and (atom? right) (= rightn ignore)) left)
           (else (cons left right)))))))
  (sub sexp))

以下是我的测试用例:

(require rackunit)

(check-equal? (butSecondLastAtom null) null)
(check-equal? (butSecondLastAtom 1) 1)
(check-equal? (butSecondLastAtom '(a b))  '(b))
(check-equal? (butSecondLastAtom '(a . b)) 'b)
(check-equal? (butSecondLastAtom '(a (b . c))) '(a c))
(check-equal? (butSecondLastAtom '(1 2 (3 (4 5 (6 . 7))))) '(1 2 (3 (4 5 7))))
(check-equal? (butSecondLastAtom '(a (b (c) d))) '(a (b () d)))
(check-equal? (butSecondLastAtom '(a (c d) e)) '(a (c) e))
(check-equal? (butSecondLastAtom '(a (b (c (d))))) '(a (b ((d)))))

答案 1 :(得分:2)

这是一个基本上复制的解决方案。从右边删除给定位置的元素的技巧是每次处理叶子时减少 n 。我们要删除的元素必须是某对的汽车,因此重建一对的复制例程部分只需要能够监视何时发生。我们可以通过返回一些特殊值而不是 n th 项来“发信号”它。我们可以使用什么特殊价值?我们已经定义了一个其他任何东西都无法访问的内部函数,因此我们可以使用它。

(define (rem n tree)
  ;; Returns a new tree similar to the input, 
  ;; but without the nth leaf from the right.
  (let rem ((tree tree))
    (cond
      ;; Copy the empty tree by returning the empty tree.
      ((null? tree)
       '())
      ;; Copy a pair by copying the right and left subtrees, 
      ;; and then putting them back together.  The exception 
      ;; is when the car is the nth element (and the "copy" of 
      ;; it is the special value).  In that case, we just
      ;; return the copy of the right subtree.
      ((pair? tree)
       (let ((r (rem (cdr tree)))  ; copy the right subtree
             (l (rem (car tree)))) ; copy the left subtree
         (if (eq? l rem)
             r
             (cons l r))))
      ;; When we encounter a leaf, decrement the counter.  
      ;; If it's zero (which means we want to discard this leaf),
      ;; then return the special value.  Otherwise, return
      ;; the leaf.
      (else
       (set! n (- n 1))
       (if (= n 0) rem tree)))))

> (rem 2 '(a (b (c (d)))))
(a (b ((d))))

之后,您可以轻松定义更具体的版本:

(define (butSecondLastAtom lst1)
  (rem 2 lst1))

> (butSecondLastAtom '(a b (c d) ((e f) (g))))
(a b (c d) ((e) (g)))