2011-04-01 83 views
1

刪除元素首次出現在列表中,我可以刪除元素的所有出現在列表中:使用列表理解

*Main> let d = [1, 2, 3, 4, 5, 6] 
*Main> d 
[1,2,3,4,5,6] 
*Main> [x | x <- d, not(x == 2)] 
[1,3,4,5,6] 

我只是想知道是否有任何可能刪除元素的唯一一次出現在列表中,但使用列表理解?

+0

我猜想像 [x |不是$ null d,x < - 尾d] 是不是你以後? – hvr 2011-04-01 06:32:33

+0

正如我所看到的,它刪除了列表中的第一個元素,它的作用類似於「尾部d」。但是我需要刪除第一個遇到的號碼(在我的例子中是'2')。 – demas 2011-04-01 06:37:37

回答

4

不,沒有。該列表理解

[ x | x <- d, GUARD ] 

相當於被定義如下:

let ok x = if GUARD then [x] else [] 
    ok _ = [] 
in concatMap ok d 

通過「如果」的定義,後衛必須是一個純粹的布爾表達式(即單獨評估爲True的假),所以它不能跟蹤狀態,因爲你在列表上映射(假設你要按照規則來玩)。

話雖如此,有一種解決方法使用解析:將狀態壓縮到輸入列表中,並在該組合列表上運行列表理解。這個複合列表可能有一種類似[(Int, Bool)]的類型,Bool表示這是否是列表中的第一項。然後,您這樣做:

[ x | (x, isFirst) <- zip d (findFirsts d), not (x == 2 && isFirst)] 

其中findFirsts d實施就留給讀者做練習。

但你不想在這種特殊情況下做到這一點。這是一個不好的解決方案,因爲它基本上意味着你至少要經歷兩次這個列表,一次找出哪些項目是第一個,並且一次實際過濾出你不想要的項目。如果你天真地實施了findFirsts,你可能會看到更多的工作。不適合這份工作!

對於某些問題,例如檢查頭部或將某個項目的特定位置合併到結果中(如hvr已經演示),這可能是一種非常有效的技術。其他

兩種方式:

  1. 使用一元計算,攜帶狀態,你依次遍歷列表。如果您想要遍歷任意或複雜的結構,或者計算將變得複雜的情況下,可能會出現問題,但在這種情況下,如果您願意,最好:

  2. 只需使用簡單的遞歸函數解決方案,這是Data.List.deletedeleteBy做什麼。

0

下刪除元素只有在發生的歷史頭部位置:

[ x | (i, x) <- zip [0..] d, if i == 0 then x /= 2 else True ] 

(這是不是問題)

+0

看起來不起作用:* Main> let d = [1,2,3,4,5,6,2,7,2] * Main> [x | (i,x)< - zip [0 ..] d,not(x == 2)|| i/= 0] [1,2,3,4,5,6,2,7,2] – demas 2011-04-01 06:41:35

+0

對不起,我第一次弄錯了,現在應該修好了 - Doh,還是錯的...現在我終於明白你在做什麼... – hvr 2011-04-01 06:42:11

+1

tbh,在迭代之間用列表理解來傳遞信息是相當麻煩的;你不得不依賴實用函數來爲你做這件事。使用列表理解類似於使用concat/map/filter的組合,其缺乏例如一個摺疊帶來了桌子。 – hvr 2011-04-01 06:48:48

3

因爲我想指出的記錄,即delete功能在Data.List模塊提供了你描述的行爲。

所以,你可以欺騙了一下,只使用delete在列表理解:

> let l = [1,2,3,2,1] 
> [x | x <- delete 2 l] 
[1,3,2,1] 

我想這不計數。

...所以,我很好奇,如何做到這一點,這裏是不使用delete一個解決方案:

-- Removes the first occurrence of '2' in 'l', if any. 
[x | (x,y) <- zip l [0..], let idx = elemIndex 2 l, idx == Nothing || y /= fromJust idx] 

的想法是先打開列表轉換成元組的列表,其中第二每個元組的元素是元素的索引,例如"abcba"變成[('a',0),('b',1),('c',2),('b',3),('a',4)]。然後,我們將第二個元組元素不等於'elemIndex'返回的值(它返回給定元素的第一個出現位置)的所有元組的每個第一個元素。例如,elemIndex 'b' "abca"產生2,所以我們採取第二個元素不是2的所有元組的第一個元素。那產量"acba"

0

不是直接。列表解析等同於僅使用concatmap。他們統一映射元素 - 如果a更改爲b(或已刪除或更改爲多個元素),則所有發生的a都會執行相同操作。

醜陋的方式將標籤與數字內容和搜索的第一個:

f r x = let x' = zip x [0..]              
      (_,n) = head [v | v <- x', fst v == r]        
     in [y | (y,m) <- x', y /= r || m /= n] 

首先zip可以用LC表示,如果你使用的擴展名「平行列表理解」。這是非常不自然的,更好地使用顯式遞歸或Data.List.delete