【发布时间】:2012-02-28 18:34:58
【问题描述】:
如果我说我有两个字符串或字符列表,
list1 = ["c","a","t"]
list2 = ["d","o","g"]
如果我使用输入输出"ct" 读取一个字符串并将其传递给函数,该函数应该返回"dg"。
请告诉我有关此类功能的任何想法。
【问题讨论】:
如果我说我有两个字符串或字符列表,
list1 = ["c","a","t"]
list2 = ["d","o","g"]
如果我使用输入输出"ct" 读取一个字符串并将其传递给函数,该函数应该返回"dg"。
请告诉我有关此类功能的任何想法。
【问题讨论】:
我会考虑获取这两个列表,将它们压缩在一起,使用Data.Map.fromList 创建一个查找映射,然后映射输入字符串并使用映射计算出替换它们的内容。
【讨论】:
lookup 和Data.Map 的精彩介绍,请参阅learnyouahaskell.com/modules#data-map
我首先假设list1 和list2 具有[Char] 类型(即String),因为这就是您的文字似乎表明的内容(您的代码将它们作为[String]s - 如果您真的想要这个,见附录中的通用版本)。
如果您zip 这两个列表,您最终会得到一个指示如何翻译字符的对列表。在您的示例中,zip list1 list2 = [('c','d'), ('a','o'), ('t','g')]。我们将把它称为我们的查找列表。现在考虑函数lookup:
lookup :: Eq a => a -> [(a, b)] -> Maybe b
在我们的例子中,我们可以将其专门用于
lookup :: Char -> [(Char, Char)] -> Maybe Char
所以我们有一些东西,它接受一个字符和一个查找列表,如果输入字符在查找列表中,则返回一个替换字符(否则为Nothing)。现在我们只需要将我们找到的东西粘合在一起:我们基本上需要将\c -> lookup c lookupList(更优雅地写为flip lookup)映射到输入字符串,同时扔掉在输入字符串中找不到的任何字符查找列表。嗯,输入mapMaybe:
mapMaybe :: (a -> Maybe b) -> [a] -> [b]
它完全符合我们的要求。现在你的函数可以写成
replace :: String -> String -> String -> String
replace list1 list2 = mapMaybe ((flip lookup) (zip list1 list2))
您需要导入Data.Maybe。
附录,当您理解上述内容时:请注意我们上面所做的与我们使用字符列表这一事实无关。我们可以用 any 类型的列表来做上面的所有事情,这对相等是有意义的,即对于任何类型的(列表)是Eq 类型类的实例(参见上面lookup 的签名)。此外,我们不必从该类型转换为自身——例如,上面的每个字符都可以发送为一个整数!所以真的,我们可以写
replace :: (Eq a) => [a] -> [b] -> [a] -> [b]
replace list1 list2 = mapMaybe ((flip lookup) (zip list1 list2))
现在只要list1 是一个对相等有意义的事物的列表,我们的函数就可以工作。替换字符只是一种特殊情况。
一个简单的例子:
> replace "cat" "dog" "ct"
"dg"
> replace "cat" [1,2,3] "ct"
[1,3]
【讨论】:
Map)将比我的基于列表的解决方案执行得更好。我故意避免引入(更适合的)Map 数据结构以使其简单,但请记住 ivanm 的解决方案更好。
replace 应用于某事?如果有,是什么?
对于两个字符串,你可以这样做:
patt :: String -> String -> String -> String
patt (x : xs) (y : ys) p'@(p : ps)
| p == x = y : patt xs ys ps
| otherwise = patt xs ys p'
patt _ _ [] = []
main :: IO ()
main = do
putStrLn $ patt "cat" "dog" "ct"
【讨论】:
patt "cat" "dog" "ctc" 给出了一个不完整的模式匹配错误,而我认为它应该返回"dgd"。