【问题标题】:How to capitalize the first letter of a string and lowercase the rest in Haskell如何在Haskell中将字符串的第一个字母大写并小写其余字母
【发布时间】:2013-11-20 10:27:03
【问题描述】:

我必须编写一个函数,将字符串的第一个字母大写,并将字符串的其余部分小写(该字符串包含随机的大写或小写字母)。

到目前为止,我已经做到了:

capitalised :: String->String
capitalised [] = []
capitalised x
            | length x == 1 = map toUpper x
            | otherwise = capitalised (init x): map toLower (last x)

还有其他各种奇怪的功能,我还是想不通。

请帮忙!提前发送!

忘了说,问题说明我需要写一个递归解决方案!

【问题讨论】:

  • 请不要在这里发布作业问题...

标签: string haskell


【解决方案1】:

还记得String 只是[Char] 的类型同义词吗?在这里我们利用它:

import qualified Data.Char as Char

capitalized :: String -> String
capitalized (head:tail) = Char.toUpper head : map Char.toLower tail
capitalized [] = []

这是一个递归版本:

capitalized :: String -> String
capitalized [] = []
capitalized (head:tail) = Char.toUpper head : lowered tail
  where
    lowered [] = []
    lowered (head:tail) = Char.toLower head : lowered tail

【讨论】:

  • 这应该是对我的问题的最简洁和正确(和快速)的答案。我非常感谢你的帮助。但是,我忘记在我的问题中提及一些关键字。该函数应以递归方式编写。有解决方案吗? TXX!
  • 所以这是作业?如果我是你,我真的宁愿自己解决。此外,它真的很琐碎。无论如何,请查看更新。
  • 是的,其实我自己刚刚解决了。对于您的持续帮助,我仍然接受您的回答。但我认为你也应该看看这个解决方案,因为它会向后处理字符串而不是capitalised :: String->String capitalised (x:[]) = [toUpper x] capitalised x = capitalised $ init x ++ [toLower $ last x] capitalised x = capitalised $ init x ++ [toLower $ last x]
  • @oasisweng 你的建议实现会很糟糕,因为last 和init 操作都需要遍历整个列表,换句话说,它们都有时间O(n) 的复杂性。您还可以在迭代的每个步骤中调用这些函数,因此总的来说,您的函数的时间复杂度为 O(n * (n + n))。另一方面,cons 操作 (:) 的复杂度为 O(1),因此我的两个解决方案的复杂度都只有 O(n)。
  • 解释得很好,tx!
【解决方案2】:

警告:这个解决方案可能有点矫枉过正,而且不适合新手,但这里是使用 lens 包中的遍历的方法。

import Control.Lens
import Data.Char

capitalize :: *really scary type would go here*
capitalize = over _head toUpper . over (_tail.each) toLower

其中_head 和_tail 来自Control.Lens.Cons,each 来自Control.Lens.Each,over 来自Control.Lens.Setter。

这个定义的好处是它应该适用于Seq、Vector、Text 和除String 之外的其他数据类型,因为它们都是Cons 和Each 的实例。例如:

import qualified Data.Text as T
import qualified Data.Sequence as S

over _head toUpper . over (_tail.each) toLower $ "aA"
-- "Aa"
over _head toUpper . over (_tail.each) toLower $ T.pack "aA"
-- "Aa"
over _head toUpper . over (_tail.each) toLower $ S.fromList "aA"
-- "Aa"

编辑:这是另一种方法,只是为了它。

import Data.Char 
import Control.Lens 
import Control.Arrow (***)

over _Cons (toUpper *** over each toLower) "aA"

【讨论】:

  • 这会比@NikitaVolkov 给出的解决方案效率低吗?肯定会有更多的开销,但理论上很多可以由编译器优化掉,因为 Lenses 几乎是内置的 Haskell 类型。
  • @bheklilr 它在列表的头部进行了两次模式匹配,而不是一次。我不知道lens 是否引入了任何重大开销,也许它已被优化掉。
  • 应该是import Control.Arrow ((***))。
【解决方案3】:

您在线出错:

| otherwise = capitalised (init x): map toLower (last x)

只使用head 和tail,而不是init 和last:

capitalised [] = []
capitalised x = 
        | length x == 1 = map toUpper x
        | otherwise     = head (capitalised [head x]) : map toLower (tail x)

这个解决方案不是最优的。 Nikita Volkov 的版本更漂亮。 或者我们可以将其重写为

capitalised [] = []
capitalised x = toUpper (head x) : map toLower (tail x)

【讨论】:

【解决方案4】:

在各种库的帮助下,有更多方法可以做到这一点:

Prelude> :m +Data.Char Data.List
> let ucfirst x = (toUpper $ head x) : (toLower <$> tail x)

Prelude> :m +Data.Char Data.List Control.Arrow
> let ucfirst = (head >>> toUpper) &&& (tail >>> (toLower <$>)) >>> uncurry (:)

Prelude> :m +Data.Char Data.List Control.Applicative
> let ucfirst = liftA2 (:) (toUpper . head) ((toLower <$>) . tail)

他们都做同样的事情:

> ucfirst "fOO"
"Foo"

【讨论】:

    【解决方案5】:

    来这里是因为我必须回答同样的问题,并想出了这个解决方案

    capitalised [] = []
    capitalised xs  | length xs == 1 = capitalised (init xs) ++ [toUpper c | c<-xs]
                    | otherwise = capitalised (init xs) ++ [toLower c | c<-xs, c == last xs]
    

    认为这是初学者可以使用的最递归的答案:)

    【讨论】:

      猜你喜欢
      • 2020-12-10
      • 1970-01-01
      • 2013-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-20
      相关资源
      最近更新 更多