我对Haskell相当新,作为输入,我想以一个字符串数组为例
["HEY" "I'LL" "BE" "RIGHT" "BACK"]
并查找允许说"BE" "RIGHT" "BACK"
并将其替换为其他字词,让我们说"CHEESE"
。我有一个单个单词的功能,但如果一个字符串包含某个短语用一个单词替换它,我想要这个。哦,我不想使用外部库。
代码:
replace :: [String] -> [String]
replace [] = []
replace (h:t)
| h == "WORD" = "REPLACED" : replace t
| otherwise = h : replace t
答案 0 :(得分:1)
您现在拥有的内容也可以实现为
replace ("WORD":rest) = "REPLACED" : replace rest
replace (x:rest) = x : replace rest
replace [] = []
这可以扩展到你的例子
replace ("BE":"RIGHT":"BACK":rest) = "CHEESE" : replace rest
replace (x:rest) = x : replace rest
replace [] = []
但显然这不是写它的好方法。我们想要一个更通用的解决方案,我们可以传入一个短语(或子列表)来替换。首先,我们了解以下事项:
n
元素的列表(在我们递归时减少)m
元素的列表(在我们递归时保持不变)m > n
,我们肯定没有匹配m <= n
,我们可能会匹配虽然有更高效的算法,但一个简单的算法就是检查列表中每一步的长度。这可以简单地完成
-- Phrase Replacement Sentence New sentence
replaceMany :: [String] -> String -> [String] -> [String]
replaceMany phrase new sentence = go sentence
where
phraseLen = length phrase
go [] = []
go sent@(x:xs)
| sentLen < phraseLen = sent
| first == phrase = new : go rest
| otherwise = x : go xs
where
sentLen = length sent
first = take phraseLen sent
rest = drop phraseLen sent
在这里,我们可以利用Haskell的懒惰,然后继续定义first
和rest
,而不必担心它是否有效。如果不使用它们,它们永远不会被计算出来。我选择在sent@(x:xs)
格式中使用一些更复杂的模式匹配。这会匹配包含至少一个元素的列表,将整个列表分配到sent
,将第一个元素分配给x
,将列表的尾部分配给xs
。接下来,我们只检查每个条件。如果sentLen < phraseLen
,那么列表的其余部分就不可能存在匹配,所以只返回整个事情。如果第一个m
元素等于我们的短语,则替换它并继续搜索,否则只需放回第一个元素并继续搜索。