使用列表推导删除列表中元素的第一个出现

时间:2011-04-01 06:28:30

标签: haskell

我可以删除列表中所有元素的出现:

*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]

我只是想知道是否有可能只删除列表中FIRST出现的元素,但是使用列表理解?

4 个答案:

答案 0 :(得分:4)

不,没有。列表理解

[ x | x <- d, GUARD ]
根据定义,

与以下内容相同:

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

通过'if'的定义,GUARD必须是一个纯布尔表达式(即单独评估为True of False),因此当你映射到列表时它无法跟踪状态(假设你要玩规则)。

话虽如此,有一种方法可以使用理解:将状态压缩到输入列表中并在该复合列表上运行列表推导。此复合列表可能具有类似[(Int, Bool)]的类型,其中Bool指示这是否是列表中的第一项。然后你做了类似的事情:

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

findFirsts d的实施作为练习留给读者。

但是你不想在这种特殊情况下这样做。这是一个糟糕的解决方案,因为它基本上意味着你要经历列表至少两次,一次找出哪些项目是第一,一次实际过滤掉你不想要的项目。如果你天真地实现了findFirsts,那么你可能会看到更多的工作而不是那些工作。这不是工作的正确工具!

对于某些问题,例如检查头部或将项目的特定位置合并到结果中(如 hvr 所示),这可能是一种非常有效的技术。

另外两种方式:

  1. 当您按顺序遍历列表时,使用monadic计算来携带状态。对于你想要遍历任意或复杂结构的情况,或者你的计算会变得复杂的情况,可能会好的,但在这种情况下,如果你这样做,你会更好:

  2. 只需使用一个简单的递归函数解决方案,这是Data.List.deletedeleteBy所做的。

答案 1 :(得分: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"

答案 2 :(得分:0)

以下仅在头部位置发生时才删除元素:

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

(这不是问题)

答案 3 :(得分: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]

如果您使用扩展名“parallel list comprehensions”,则可以使用LC表示第一个zip。这非常非惯用,更好地使用显式递归或Data.List.delete