在Haskell中从字符串列表中删除一个字符串

5
我有一个关于Haskell的问题一直困扰着我。我目前需要编写一个函数,从字符串列表中删除一个字符串,例如"word"["hi", "today", "word", "Word", "WORD"]列表中, 返回列表["hi", "today", "Word", "WORD"]。我不能使用任何高级函数,只能采用基本递归。
思考这个问题时,我想也许可以使用递归来解决,你搜索第一个字符串的头部,如果它匹配"w",那么比较尾部的下一个头部,看看它是否匹配"o"。但很快我意识到,经过所有这些工作后,你将无法删除完整的字符串"word"
我的问题实际上是如何比较列表中的整个字符串而不仅仅是每次比较一个元素,例如: removeWord(x:xs)。这是否可能?我需要编写一个辅助函数来帮助解决吗?

2
你的列表包含字符串并不是真正重要的。首先尝试解决整数列表的问题,然后只需更改类型签名即可使其适用于字符串列表。 - hammar
4
当你将(x:xs)["hi", "today", "word", "Word", "WORD"]进行匹配时,x变成了"hi",而xs变成了["today", "word", "Word", "WORD"]。也就是说,这种匹配方式是逐个字符串匹配的,而不是逐个字符匹配的。这种方法之所以行得通,是因为你有一个字符串列表,而不仅仅是一个大字符串。 - Tikhon Jelvis
1
哦,我明白了!非常感谢您,这就是我的问题所在。我以为只是第一个元素,而不是整个单词。这解决了所有的问题! - Phirip
4个回答

3

如果你想要移除一个列表元素,可以使用列表推导式来轻松实现。

myList = ["hi", "today", "word", "Word", "WORD"]
[x | x <- myList, x /= "word"]

结果如下:
["hi","today","Word","WORD"]

3
考虑基本情况:从空列表中删除一个单词将得到空列表。可以简单地编写如下代码:
removeWord [] _ = []

现在考虑列表不为空的情况。您可以使用x:xs匹配。您可以使用保护程序在这两个条件之间进行选择:
  1. x是要删除的单词。(x == word
  2. x不是要删除的单词。(otherwise

我以为对于'(x:xs)',x只会匹配列表中的第一个元素,所以在["Hi", "word"]中,x会返回H,不是吗? - Phirip
1
@Phirip:["Hi", "word"] 是一个包含两个元素的列表。第一个元素是 "Hi",第二个元素是 "word"。对于 (x:xs)x 将会是 "Hi"。只有在使用 ((x:xs):ys) 时才能获得 H - icktoofay
哦,我明白了!非常感谢,这就是让我困扰的地方。我以为只是第一个元素而不是整个单词。这解决了所有问题! - Phirip
2
@Phirip: “Hi”[“Hi”, “word”]中的第一个元素。'H'“Hi”的第一个元素。‘H’将成为[“Hi”, “word”]第一个元素中的第一个元素,而冒号:仅向下一级。 - icktoofay

3
你不需要一个辅助函数,虽然如果你愿意可以编写一个。你基本上有3个条件:
  1. 你得到了一个空的列表。
  2. 你得到了一个列表,其第一个元素是你想要删除的元素。
  3. 你得到了一个列表,其第一个元素是其他任何东西。
在其他语言中,你可以用一系列的if-else语句、case语句或者cond来实现这个功能。在Haskell中,你可以使用guards来实现:
remove_word_recursive:: String -> [String] -> [String]
remove_word_recursive _ []                              = []
remove_word_recursive test_word (x:xs) | test_word == x = what in this case?
remove_word_recursive test_word (x:xs)                  = what in default case?

在这两种条件下填写此函数的正确结果,然后你就完成了。

我认为你所寻找的是该问题中有关字符串过滤器的函数的特殊情况:Haskell - filter string list based on some conditions。阅读一些有关已接受答案的讨论可能会帮助你更好地理解 Haskell。


3
请不要推广使用下划线命名法 (underscore_naming_convention),驼峰命名法 (camelCaseConvention) 似乎是事实上的标准。 - dflemstr
啊,好的。我不知道Haskell社区的标准是什么,而且在我所处的语言中,“underscore_naming_convention”是跨语言的标准。那么为什么“camelCaseConvention”对于Haskell更优秀的讨论在哪里呢? - pcurry
2
Haskell编程指南是某种权威来源,base库(包括Prelude)使用该命名约定编写,Hackage上的大多数Haskell库也是如此。下划线通常保留给丢弃值的函数版本(例如,mapM_而不是_ <- mapM)。 - dflemstr

1
如果isInfixOf不被视为高阶函数,那么
import Data.List (isInfixOf)
filter  (not . isInfixOf "word")  ["hi", "today", "word", "Word", "WORD"]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接