【问题标题】:Haskell function that takes out last occurrence of input character取出最后一次出现的输入字符的 Haskell 函数
【发布时间】:2016-02-14 11:08:31
【问题描述】:

我在编写这个函数时遇到了麻烦,它接受一个字符和一个字符列表,然后消除该输入字符在列表中的最后一次出现。我能够使用下面的函数取出第一次出现的输入字符:

fun :: Char -> String -> String
fun c (s:ss)
 | s == c   = ss
 | otherwise = s : fun c ss
fun _ [] = []

我需要帮助的是我应该如何修改这个函数来取出输入字符的最后一次出现,而不是第一次出现。结果应该类似于fun 'c' "abcdccytrc" 返回"abcdccytr"。

【问题讨论】:

  • 如何反转字符串,然后使用您的函数?这可能不是您想要的,但它会起作用。
  • 我正在考虑这个问题,我确实尝试过,但我试图将它全部保存在一个函数中。
  • 是的,这就是我试图在一个函数中回答的原因。但正如 Will Ness 和 chi 对我的回答所评论的那样,有更好的解决方案。如果您将接受的答案切换为 @SimonShine 的答案,我会更喜欢它,但谢谢!

标签: string list function haskell winghci


【解决方案1】:

正如 Numeri 所建议的,通过删除反向列表中的第一个匹配项来删除最后一个匹配项是一种方法:

removeFirst :: Char -> String -> String
removeFirst _ [] = []
removeFirst c1 (c2:cs) = if c1 == c2 then cs else c2:removeFirst c1 cs

removeLast :: Char -> String -> String
removeLast c1 = reverse . removeFirst c1 . reverse

正如 Will Ness 所建议的,返回删除最后一次出现的字符串,以及指示是否应该删除当前出现的布尔值是另一个:

removeLast :: Char -> String -> String
removeLast c1 = snd . remLast
  where
    remLast :: String -> (Bool, String)
    remLast [] = (False, [])
    remLast (c2:cs) =
      case remLast cs of
        (True, cs') -> (True, c2:cs')
        (False, cs') -> if c1 == c2 then (True, cs') else (False, c2:cs')

【讨论】:

    【解决方案2】:

    好的,这就是我想出的:

    fun :: Char -> String -> String
    fun c (s:ss)
     | ((fun c ss) == ss) && (s == c) = ss
     | otherwise                      = s : fun c ss
    fun _ [] = []
    

    本质上,如果s == c,并且字符串的其余部分(ss)通过在其上运行此函数没有改变(即,它不包含字符c),则返回剩余的字符。

    如果不满足此要求(即字符串的其余部分至少有一次字符 c),则保留当前字符并将函数应用于字符串的其余部分。

    除此之外,我认为反转字符串然后调用原始函数,然后再次反转它,就像我在评论中建议的那样,可能更容易理解,但这只是意见。

    【讨论】:

    • 将结果与原始字符串进行比较将使您的函数总体上以二次时间运行。但是你不需要比较来找出结果——首先是你建造了它。您只需要向自己发出信号,无论该角色是否已被删除。为此,您可以返回 (String,Bool) 或 Either String String 值。
    • 看起来效率很低。每次调用两次递归调用似乎表明指数复杂性。考虑递归调用应该使其成为二次方,这与您通过逆向获得的线性复杂度仍然相去甚远。
    • @chi 是的,我知道它非常低效,但实际上我才刚刚开始学习 Haskell:我想尝试返回一个布尔值来改进这一点,但我不知道该怎么做在哈斯克尔。这实际上也是我建议反转字符串的原因。
    • @WillNess ...事实上,由于这些原因(效率低下和更好的编码),我实际上认为OP应该接受下面西蒙的回答。
    猜你喜欢
    • 2017-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-08
    • 2011-07-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多