我想在你的代碼的主要問題是對列表的cdr
使用null?
或cdr
,無論是在flatten
和butLast
。不要這樣做;總是使用列表本身的過程和謂詞。
我建議如下:
壓扁列表
大多數方案有一個版本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 '())
'()
對於不壓平,見http://stackoverflow.com/questions/25827250/deleting-second-last-atom/25828080#25828080 – uselpa 2014-09-14 07:43:45