将列表的每个元素与另一个列表的每个元素进行比较

时间:2019-12-04 00:25:58

标签: haskell

我正在尝试编写一个函数,该函数采用第一个字符串的第一个字符,将其与第二个字符串的所有字符进行比较,如果找到相同的字符,则将其替换为“-”。然后,它移至第一个字符串的第二个字符,对第二个字符串上的每个字符(除了第一个字符-我们已经检查过的那个字符)进行相同的比较,依此类推。我希望它返回第一个字符串,但是将重复的字符替换为符号“-”。

例如如果我输入comparing "good morning" "good afternoon",我希望它返回"-----m---i-g"

我希望我解释得足够清楚。到目前为止,我已经:

comparing :: String -> String -> String
comparing a b =
    if a == "" then ""
    else if head a == head b then "-" ++ (comparing (tail a) (tail b))
    else [head a] ++ (comparing (tail a) b)

问题是它不会逐个字符地通过第二个字符串,而且我不确定如何实现。我想我需要在第四行调用递归函数:

if head a == ***the first character of tail b*** then "-" ++ (comparing (tail a) (tail b))

该功能看起来像什么?还是有更好的方法来做到这一点?

2 个答案:

答案 0 :(得分:3)

首先,在每个递归调用中,当您遍历字符串a时,出于某种原因,您同时也在遍历字符串b 。看:您仅将tail b传递给下一个呼叫。这意味着下一个调用将无法通过整个字符串b进行查看,而只能通过其尾部进行查看。你为什么要这样做?

第二,为了查看字符串中是否存在字符,请使用elem

elem 'x' "xyz" == True
elem 'x' "abc" == False

因此,函数的第二行应如下所示:

    else if elem (head a) b then "-" ++ (comparing (tail a) b)

在某种程度上相关的注释上,headtail函数的使用有些皱眉,因为它们是局部的:如果字符串为空,它们将崩溃。是的,我发现您已经检查过以确保该字符串为 not 为空,但是编译器无法理解该字符串,这意味着当您不小心更改字符串时,它将无法捕获您以后再检查。

检查数据的更好方法是通过模式匹配:

-- Comparing an empty string with anything results in an empty string
comparing "" _ = "" 
-- Comparing a string that starts with `a` and ends with `rest`
comparing (a:rest) b = 
    (if elem a b then "-" else a) ++ comparing rest b

答案 1 :(得分:1)

这看起来像手动map的经典用例,而不是手动编写递归逻辑。您只需要一个函数,该函数需要一个字符并根据另一个列表中的字符来返回该字符或'-'

完全写出来,看起来像这样:

comparing first second = map replace first
  where replace c = if c `elem` second then '-' else c