2009-12-08 58 views
2

給定一個列表,我嘗試返回一個新的項目,該項目只有在我作爲參數接收的第一個列表中出現多次的項目。作業:在列表中多次出現的Lisp項目

我也做了以下內容:

(defun myf (lista) 
    (if (endp lista) 
     nil 
     (if (member (first lista) (rest lista)) 
      (append (list (first lista)) (myf (rest lista))) 
      (myf (rest lista))))) 

如果我運行以下命令:(myf '(A A B A B C)),它返回(A A B)。 我該如何讓它只返回一次(即沒有雙「A」)?

+2

鏈式IF形式可以更好地轉換爲COND。 – Svante 2009-12-08 16:59:18

回答

2

Vincent,Gishu和Jerry暗示您需要檢查項目是否已添加到結果列表中,而Derek暗示您可以在看到項目重複時修改原始列表。

閱讀的功能adjoinremove這裏的文檔:

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)consadjoin可以做同樣的事情,但只有當它不在列表中時,adjoin纔會添加該值。

希望這給你一些玩的東西。

+0

謝謝你的解釋 – daniels 2009-12-08 20:47:02

3

問題似乎是您正在檢查列表的第一個元素是否在列表的尾部並將其附加到結果列表中。當你來到A的第二個實例時,問題就出現了,當選中時,表示它是在尾部,因爲在列表中有A的第三個實例。如果輸入列表有4個A,那麼它會返回3個。

所以解決這個需要檢查A是否已經是結果列表的成員。也就是說,如果第一個列表不是列表的成員,那麼將第一個列表追加到列表中。

2

問題似乎是,在追加到元素之前,您沒有檢查元素是否存在於輸出列表中。

+0

是的,這就是我不知道它,如何檢查,而不使用變量(即:設置,讓等..) – daniels 2009-12-08 15:28:08

+0

如何將A的所有實例從「其餘lista」中刪除一旦你'已經選擇A作爲重複? – Gishu 2009-12-08 15:31:25

3

一旦您發現一封信不止一次出現在列表中,您無需再次檢查,因此您不需要在列表的其餘部分查看該信件。所以你可以修改剩下的清單...

注意:這個答案故意有點模糊,因爲它是作業和所有。 :)

1

現在,對於列表中的每個元素,如果元素不包含在列表的其餘部分中,則將該元素添加到結果中。

爲了獲得您顯然想要的結果,如果結果中尚未包含結果中的每個元素,請將結果中的每個元素添加到結果中。

1

如果訂單不是問題,那麼你也可以這樣做:

(defun my-fun-no-order (lst) 
    (loop for (item . rest) on lst 
    when (= (count item rest) 0) 
    collect item)) 

在這裏,我們遍歷它吐到當前列表中的項上迭代和其餘項目還有待檢驗。 when子句決定我們收集物品的情況。

相關問題