list 学习 Haskell:如何从 Haskell 的列表中删除项目
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2097501/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Learning Haskell: How to remove an item from a List in Haskell
提问by BM.
Trying to learn Haskell. I am trying to write a simple function to remove a number from a list without using built-in function (delete...I think). For the sake of simplicity, let's assume that the input parameter is an Integer and the list is an Integer list. Here is the code I have, Please tell me what's wrong with the following code
尝试学习 Haskell。我正在尝试编写一个简单的函数来从列表中删除一个数字而不使用内置函数(删除......我认为)。为了简单起见,我们假设输入参数是一个整数,列表是一个整数列表。这是我的代码,请告诉我以下代码有什么问题
areTheySame :: Int -> Int-> [Int]
areTheySame x y | x == y = []
| otherwise = [y]
removeItem :: Int -> [Int] -> [Int]
removeItem x (y:ys) = areTheySame x y : removeItem x ys
回答by Chuck
The others are right that the problem is the :
operator. I would say that your areTheySame
function that returns a list is the wrong approach anyway, though. Rather than switch to the ++
operator, a better implementation of that function would be:
其他人是对的,问题是:
运营商。不过,我会说您areTheySame
返回列表的函数无论如何都是错误的方法。与其切换到++
运算符,该函数的更好实现是:
removeItem _ [] = []
removeItem x (y:ys) | x == y = removeItem x ys
| otherwise = y : removeItem x ys
As you can see, this is a pretty simple implementation. Also, consing like this is much less taxing for your program than appending a bunch of lists together. It has other benefits as well, such as working lazily.
如您所见,这是一个非常简单的实现。此外,像这样的 cons 对您的程序来说比将一堆列表附加在一起要少得多。它还有其他好处,例如懒惰地工作。
回答by Chris Lutz
The :
operator doesn't do what you think it does:
该:
运营商没有做什么你认为它的作用:
(:) :: a -> [a] -> [a]
It takes an item of type a
and adds it to the beginning of a list of type a
. You're using it to join two lists of type a
. For that, you need to use ++
:
它接受一个 type 项a
并将其添加到 type 列表的开头a
。您正在使用它来连接两个类型为 的列表a
。为此,您需要使用++
:
(++) :: [a] -> [a] -> [a]
Also, if you make a recursive function, it needs an ending condition. So try this:
另外,如果你创建一个递归函数,它需要一个结束条件。所以试试这个:
removeItem _ [] = []
removeItem x (y:ys) = areTheySame x y ++ removeItem x ys
That way, when you get to the end of the list, the function will stop recursing.
这样,当您到达列表末尾时,该函数将停止递归。
回答by Dagititis
You can also do this as a list-comprehension
您也可以将其作为列表理解来执行
delete :: Eq a => a -> [a] -> [a]
delete deleted xs = [ x | x <- xs, x /= deleted ]
回答by Juan Carlos Kuri Pinto
I wrote a function in just one line of code:
我只用一行代码写了一个函数:
remove element list = filter (\e -> e/=element) list
For example:
例如:
remove 5 [1..10]
[1,2,3,4,6,7,8,9,10]
[1,2,3,4,6,7,8,9,10]
remove 'b' ['a'..'f']
"acdef"
“acdef”
回答by ahans
This is the minimal fix to make your example work:
这是使您的示例工作的最小修复:
removeItem :: Int -> [Int] -> [Int]
removeItem _ [] = []
removeItem x (y:ys) = areTheySame x y ++ removeItem x ys
First, you need to use ++
to concatenate lists, as the :
operator used by you adds just one element to the beginning of a list (it can neither be used to add lists with one element nor to add empty lists). You first compare the head of the list (y
) to the item you want to remove and correctly return the item or an empty list using areTheySame
. Then you want to recursively continue using removeItem
on the rest of the list (ys
). The resulting list needs to be concatenated using ++
.
首先,您需要使用++
连接列表,因为:
您使用的运算符仅将一个元素添加到列表的开头(它既不能用于添加具有一个元素的列表,也不能用于添加空列表)。您首先将列表的头部 ( y
) 与要删除的项目进行比较,然后使用 正确返回该项目或空列表areTheySame
。然后您想递归地继续使用removeItem
列表的其余部分 ( ys
)。结果列表需要使用连接++
。
Second, as Chris Lutz noted, you need an ending condition when you reach the end of the list. By adding this line, Haskell knows what to do with an empty list (that is, nothing, just return an empty list).
其次,正如 Chris Lutz 所指出的,当您到达列表末尾时,您需要一个结束条件。通过添加这一行,Haskell 知道如何处理一个空列表(即什么都不做,只返回一个空列表)。
As Chuck said, you can simplify the code for this task by having removeItem not delegate the task of the comparison, but compare itself and throw away the element if it should be removed, otherwise keep it at the list head (using :
). In any case, continue recursively with the rest of the list.
正如查克所说,您可以通过让 removeItem 不委托比较任务来简化此任务的代码,而是比较自身并在应该删除元素时将其丢弃,否则将其保留在列表头部(使用:
)。在任何情况下,递归地继续处理列表的其余部分。
-- nothing can be removed from an empty list
-- ==> return empty list and stop recursion
removeItem _ [] = []
-- if the list is not empty, cut off the head in y and keep the rest in ys
-- if x==y, remove y and continue
removeItem x (y:ys) | x == y = removeItem x ys
-- otherwise, add y back and continue
| otherwise = y : removeItem x ys
回答by Greg Bacon
For reference, you may be interested in seeing how it's done in delete
from Data.List.
作为参考,您可能有兴趣从 Data.List中查看它是如何完成的delete
。
You could leave areTheySame
as is, but you'd then need to use concatMap
in removeItem
to collapse the empty lists:
您可以保持areTheySame
原样,但您需要使用concatMap
inremoveItem
折叠空列表:
removeItem :: Int -> [Int] -> [Int]
removeItem x xs = concatMap (areTheySame x) xs
or equivalently
或等效地
removeItem :: Int -> [Int] -> [Int]
removeItem x = concatMap (areTheySame x)
Note that the types of your functions could be more general:
请注意,您的函数类型可能更通用:
areTheySame :: (Eq a) => a -> a -> [a]
removeItem :: (Eq a) => a -> [a] -> [a]
This allows removal of items from lists of any type for which ==
is defined, not just Int
.
这允许从==
定义的任何类型的列表中删除项目,而不仅仅是Int
.
回答by tphyahoo
I believe all the solutions given so far work differently than Data.List.delete, which only deletes the first member.
我相信到目前为止给出的所有解决方案都与 Data.List.delete 不同,后者只删除第一个成员。
deleteFromList x xs =
case break (==x) xs of
(_,[]) -> xs
(notsat,sat) -> notsat ++ tail sat
was my attempt to delete only the first member (haven't peaked at D.L yet).
是我试图只删除第一个成员(还没有达到 DL 的峰值)。
It's unclear which behavior the top poster wants.
目前尚不清楚顶级海报想要哪种行为。