Vincent,Gishu和Jerry暗示您需要檢查項目是否已添加到結果列表中,而Derek暗示您可以在看到項目重複時修改原始列表。
閱讀的功能adjoin
和remove
這裏的文檔:
http://www.lispworks.com/documentation/HyperSpec/Body/f_adjoin.htm
http://www.lispworks.com/documentation/HyperSpec/Body/f_rm_rm.htm
的HyperSpec是一個非常有用的參考,將其添加書籤。
這兩個函數不會修改它們的參數,而是將結果作爲新列表返回。還有其他的功能可以修改他們的論點,因此可能會更有效率,但在這一點上,也許你不應該擔心它們。
好的,我希望在寫這篇文章的時候你已經明白了。如果不是,繼續嘗試,那是你真正學習的唯一方法。
現在我想談談另一種方法,那就是通過遞歸調用來實現結果。
我們的功能repeated
會做什麼,但調用輔助功能repeatedr
這將做實際工作,傳遞給它的初始空的結果'()
:
(defun repeated (lst)
(repeatedr lst '()))
現在,讓我們定義的輔助函數,它接收兩個參數:搜索重複項的列表以及我們將累積重複項的結果列表。
(defun repeatedr (lst result)
(if (null lst)
result
(if (member (first lst) (rest lst))
(repeatedr (rest lst) (adjoin (first lst) result))
(repeatedr (rest lst) result))))
當條件(member (first lst) (rest lst))
成立,我們將毗第一項至result
,而毗鄰的將被傳遞給遞歸調用作爲第二個參數的結果;否則我們只是將result
按原樣傳遞給遞歸調用。
當列表最後爲空時(if (null lst)
我們將返回result
。
> (repeated '(a a b a b c))
(B A)
注意,結果是(B A)
,也許你期待它是(A B)
。嘗試使用筆和紙跟隨遞歸調用的執行和每次調用時的參數值,這將是一個很好的練習,並且您必須使用adjoin
來了解其行爲。如果你想要得到的結果相反,你可以修改的功能是這樣的:
(defun repeatedr (lst result)
(if (null lst)
(reverse result)
(if (member (first lst) (rest lst))
(repeatedr (rest lst) (adjoin (first lst) result))
(repeatedr (rest lst) result))))
這反向 S中的結果,當遞歸結束。
現在,在下一步之前如何從列表中刪除重複的元素?我們可以寫我們的功能是這樣的:
(defun repeatedr (lst result)
(if (null lst)
result
(if (member (first lst) (rest lst))
(repeatedr (remove (first lst) lst) (cons (first lst) result))
(repeatedr (rest lst) result))))
嘗試在REPL與remove
玩:
> (remove 'a '(a b c d a e f b a d))
(B C D E F B D)
請注意,我們不再毗荷蘭國際集團的結果,而不是我們只是創建一個新的「cons cell」與(cons (first lst) result)
。 cons
和adjoin
可以做同樣的事情,但只有當它不在列表中時,adjoin纔會添加該值。
希望這給你一些玩的東西。
鏈式IF形式可以更好地轉換爲COND。 – Svante 2009-12-08 16:59:18