注:在你的問題一個小歧義時x
已經發生多個倍,在最初的名單做什麼。我認爲這不會發生,如果是這樣,只有第一個發生被刪除。意思是removeElemOrAdd 2 [4,2,5,2,7]
將導致[4,5,2,7]
。此外,未指定應添加項目的位置。因爲它有一些優點,所以我選擇在列表末尾執行此操作。
,而無需使用任何文庫方法的實施方案如下:
removeElemOrAdd :: Eq a => a -> [a] -> [a]
removeElemOrAdd x (y:ys) | x == y = ys
| otherwise = y : removeElemOrAdd x ys
removeElemOrAdd x _ = [x]
或更短的版本:
removeElemOrAdd :: Eq a => a -> [a] -> [a]
removeElemOrAdd x = reoa
where reoa (y:ys) | x == y = ys
| otherwise = y : reoa ys
reoa _ = [x]
或等效的實現(見下文討論):
removeElemOrAdd :: Eq a => a -> [a] -> [a]
removeElemOrAdd x = reoa
where reoa (y:ys) | x == y = ys
| otherwise = y : reoa ys
reoa [] = [x]
該函數的工作原理如下:如果我們談論的是至少有一個ite的列表m (y:ys)
,我們將x
與y
進行比較,如果它們相等,則返回ys
:在這種情況下,我們已經移除了該元素,我們完成了。
現在的情況下,這兩個不相等,我們在頭返回一個列表建設(:)
與y
,因爲我們需要保留y
和尾部,我們會做一個遞歸調用removeElemOrAdd
與x
和ys
。事實上:有可能尾部ys
中的某個地方有x
需要移除,而且如果不發生,我們還需要將x
添加到列表中。
該子句將通過列表遞歸循環。從發現y
的那一刻開始,x == y
它將刪除那個y
。然而,我們可能會到達名單的最後,並且仍然沒有找到要素。在這種情況下,我們會調用最後的條款。在這裏我們知道列表是空的(我們可以寫成removeElemOrAdd x []
),但爲了使函數定義在語法上總體上,我選擇使用下劃線。如果我們未能在列表中找到x
,那麼我們只能達到此狀態,因此我們通過返回[x]
將其添加到列表尾部。
這種方法優於使用if-then-else
的優點是它可以一次完成所有任務(檢查,刪除和添加),使其更有效。
另一個優點是可以在「無限」列表上運行(例如素數列表)。這個列表是懶惰評估的,所以如果你想取前三項,這個函數只會檢查前三項的相等性。
什麼樣的「清潔」你尋求的?關於簡潔性,您的解決方案看起來不錯。關於性能,您可以掃描一次查看,刪除和添加列表,但時間會更長。 (順便說一句對稱性設計打破:你刪除所有匹配的元素,但只添加一個) – 9000
一般情況下,這看起來對我好 - 你可以我想使用的,而不是一個後衛的的if/then/else語句,但它會運行同樣的方式(遞歸),這是'haskellish'。 @ 9000通過 – Hamish
說明了這裏的對稱性,如果元素出現兩次或更多次會怎麼樣? –