2013-02-04 44 views
2

我是Haskell的新手,一直试图获取基础知识。从列表中删除x的第一个实例

假设我有以下列表Y:

3:3:2:1:9:7:3:[]

我试图找到一种方法来删除的3名单y中的第一次出现。这可能使用简单的列表理解吗?

我想什么(这个方法删除所有实例从列表):

deleteFirst _ [] = [] 
deleteFirst a (b:bc) | a == b = deleteFirst a bc 
        | otherwise = b : deleteFirst a bc 
+0

'3:3:2:1:9:7:3'不是一个列表。你可能意味着'[3,3,2,1,9,7,3]'其是用于句法舒加'3:3:2:1:9:7:3:[]' –

+0

感谢指出了这一点。对不起,这是一个错字,请参阅编辑。 – AnchovyLegend

+1

您试图重新实现'Data.List.delete',它被定义为'deleteBy(==)'。如果你被困住了,你总是可以[看看Hackage上的源代码](http://hackage.haskell.org/packages/archive/base/latest/doc/html/src/Data-List.html #deleteBy)。 – David

回答

3

作为其他已经提到的列表理解不是一个适当的解决这个任务(难以终止一步执行)。

你几乎写正确的解决方案,只需在匹配的价值平等的,你必须通过不匹配的元素返回列表的其余部分终止计算的情况下:

deleteFirst _ [] = [] 
deleteFirst a (b:bc) | a == b = bc 
        | otherwise = b : deleteFirst a bc 

> print $ deleteFirst 3 (3:3:2:1:9:7:3:[]) 
> [3,2,1,9,7,3] 
+0

呃,我看到sepp2k和Joachim Breitner已经提到了修复。 –

+0

不是前奏有内置的吗? – theonlygusti

2

我不相信这是可能的(在任何习惯的方法至少不会)与列表理解来做到这一点。你的deleteFirst的作品差不多。您需要修改的是在第一次匹配后停止删除,即在第一个子句中将deleteFirst a bc替换为bc

6

不,使用列表理解是不可能的。在列表理解中,您仅根据该元素来决定保留哪个元素。在你的例子中,你想对待你遇到的前3个不同于其他3个(因为你只想删除第一个),所以决定不依赖于单独的元素。所以列表理解不起作用。

您使用递归函数的尝试已经非常接近,除非如您所说,它会删除所有实例。为什么它会删除所有实例?因为在删除第一个之后,您会在列表的其余部分再次调用deleteFirst,这将删除下一个实例等等。要解决这个问题,请在删除第一个实例后再次调用deleteFirst。所以在这种情况下只需使用bc而不是deleteFirst a bc

0

sepp2k的有关言论列表理解是重要的事情要了解;像mapfilterfoldr等对待所有列表项统一列表操作,并了解关于他们最重要的事情是什么样的信息可以在每一个步骤,以及如何每一步的结果与其他步骤相结合。

但我想强调的一点是,我认为你应该真的试图解决这些问题的库函数方面。从this older answer of mine解决方案适应您的问题:

deleteFirst x xs = beforeX ++ afterX 
    -- Split the list into two pieces: 
    -- * prefix = all items before first x 
    -- * suffix = all items after first x 
    where (beforeX, xAndLater) = break (/=x) xs 
      afterX = case xAndLater of 
        [] -> [] 
        (_:xs) -> xs 

诀窍是,break已经内置了它的“达人第一击”的行为。作为进一步的练习,你可以尝试编写你自己的版本break;学习如何编写这些小的,通用的和可重用的函数总是有益的。

相关问题