【问题标题】:Repeating each successive element in the input list one more than the previous element重复输入列表中的每个连续元素比前一个元素多一个
【发布时间】:2015-12-02 13:55:48
【问题描述】:

我想重复输入字符串中的每个连续字符,比前一个字符多一个,从第一个字符的一次出现开始:

例如

rep "abcd" == "abbcccdddd"

我为 编写了此代码,但这不适用于 String,但会为 IntChar 生成正确的结果。

rep [] =[]
rep (x:xs) =[ (x:xs)!!y| y<-[0..(length xs)]  , _<- [1..y+1]]

我该如何解决这个问题?

【问题讨论】:

    标签: string list haskell


    【解决方案1】:

    您可以先将zip 列表[1..] 与您的列表一起应用,然后应用replicateconcat 结果:

    rep xs = concatMap (uncurry replicate) $ zip [1..] xs
    

    示例运行:

    Prelude> let rep xs = concatMap (uncurry replicate) $ zip [1..] xs
    Prelude> rep "abcd"
    "abbcccdddd"
    

    这个想法很简单,我们将每个元素与它应该重复的次数相关联。

    zip 函数的类型为[a] -&gt; [b] -&gt; [(a, b)],因此它接受两个列表并返回一个配对列表,其中第一个元素来自第一个列表,第二个元素来自第二个列表。在我们的例子中,结果的类型为 [(Int, a)]a,具体取决于参数。

    replicate :: Int -&gt; a -&gt; [a] 函数接受一个表示长度的整数和一个元素x,并生成一个给定长度的列表[x, x, x, ..., x]

    uncurry 函数接受一个 a -&gt; b -&gt; c 类型的函数,即有两个参数,并将其转换为一个类型为 (a, b) -&gt; c 的函数,即一个参数是一个元组。所以uncurry replicate 的类型为(Int, a) -&gt; [a]

    现在类型匹配,您可以通过ziped 列表的map 函数获得[[a]],然后使用concat 连接结果。 concatMap 只是 concat . map 的简写。

    您可以使用zipWith 函数,而不是使用zip,然后使用maping:

    rep xs = concat $ zipWith replicate [1..] xs
    

    请注意,您的解决方案似乎工作正常:

    Prelude> let rep [] = []; rep (x:xs) = [ (x:xs)!! y | y <- [0..length xs], _<-[1..y+1]]
    Prelude> rep [1,2,3]
    [1,2,2,3,3,3]
    Prelude> rep "abcd"
    "abbcccdddd"
    

    如果您有一个未产生正确结果的示例,请将其发布在您的问题中

    但是效率低下。处理列表时应避免使用!!length,而更喜欢mapfolds 之类的内容。

    此外,我不相信上述函数可以为[Int] 产生正确的结果,但不能为String 产生正确的结果,原因很简单:该函数是多态的,因此通过参数化,元素的类型无关紧要列表包含的内容,仅与长度有关,结果将始终具有相同的形状(如果您看到该函数从不“查看”/“操作”元素,它只是移动它们;它做的事情完全相同独立于它们的特定类型。)

    【讨论】:

    • rep = concat . zipWith replicate [1..] 有点短。
    • @user3237465 你是对的。不知道为什么我没有想到我应该使用它。
    猜你喜欢
    • 2017-01-15
    • 2015-12-16
    • 2017-03-05
    • 2019-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-11
    • 2021-10-23
    相关资源
    最近更新 更多