Deleting Second last ATOM

这一生的挚爱 提交于 2020-01-06 13:52:58

问题


I am trying to delete second last ATOM from the given list -

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

This code do delete the second last atom but fails for following condition - if input is like (a (b (c (d)))) then output should result in (a (b ((d)))). Please update where i am being wrong or with a solution.


回答1:


Here's a solution that's basically copying a tree. The trick to removing an element at a given position from the right is to decrement n each time we process a leaf. The element that we want to remove must be the car of some pair, so the part of the copying routine that rebuilds a pair just needs to be able to watch for when that happens. We can "signal" it by returning some special value instead of the nth item. What special value can we use? We've already defined an internal function that nothing else will have access to, so we can use it.

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

After that, it's easy to define your more specific version:

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

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



回答2:


The following works for my understanding of the problem, but since you provide only one testcase please make sure this is what you want.

The solution has 2 passes:

pass 1 - count the number of atoms

Fairly classical, count how many atoms we have so that we can compute which one to drop later on:

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

pass 2 - copy without the second last

First, I need an atom? predicate here:

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

Copying without dropping any element is very similar to the previous function:

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

In order to drop an element, we need to change the second clause, and introduce a counter so that we know when we meet the element to drop:

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

Here are my test cases:

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


来源:https://stackoverflow.com/questions/25827250/deleting-second-last-atom

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!