【问题标题】:Haskell string manipulationHaskell 字符串操作
【发布时间】:2019-08-28 00:54:19
【问题描述】:

我正在尝试创建一个函数,它结合给定整数列表的字符串。例如,假设给定函数[1,2,3],那么输出将是" ***"。基本上,每个数字代表一个*,前面有空格。所以数字 5 将是 " *",即 4 个空格后跟 *。但是,我得到了一个列表,我不能把它们都++ 放在一起,因为字符串会打乱顺序。

我的想法是从获取列表中的第一个元素开始,然后递归地将其作为字符串发送回来。所以对于[1,2,3],我会用String = " *" 发送回函数[2,3]。接下来,对于每个元素,我检查字符串 -1 的长度是否为 <= 下一个元素(- 1 因为包含 0)。在我提供函数的列表中,情况总是如此(列表总是从 0 到 9 的数字,递增,并且没有重复)。然后我将++原来的字符串再次调用到函数中来做递归语句。我这样做直到什么都没有了。这是我所做的:

makeStr :: [Integer] -> String -> String
makeStr [] _ = ""
makeStr (x:xs) s
        | null xs && s == ""               = getStar ((fromIntegral x)) "*"
        | null xs && s /= ""               = s ++ getStar ((fromIntegral x) - (length s)) "*"
        | s == ""                          = makeStr xs (getStar ((fromIntegral x) - ((length s))) "*")
        | length s - 1 <= (fromIntegral x) = s ++ makeStr xs (getStar ((fromIntegral x) - ((length s))) "*")

注意:getStar 是一个简单的函数,它接受一个数字和“*”并返回带有正确空格数量的字符串。它具有getStar :: Int -&gt; String -&gt; String 的声明。这个功能很好用,我已经测试过很多次了,我真的不相信这是问题所在,所以我没有包含它。

getStar 函数的一个例子是:

getStar 3 "*"
"   *"

一些具有预期输出的示例输入:

makeStr [1,2,3] ""
" ***"

makeStr [0,2,3] ""
"*  **"

makeStr [1,2,3,4] ""
" ****"

makeStr [0,9] ""
"*        *"

对于超过 2 个元素的任何列表,我的程序的输出都不正确。

makeStr [0,1] "" -- correct
"**"

makeStr [1,2,3] "" -- incorrect, should be " ***"
" **  *"

makeStr [1,2,3,4] "" -- incorrect, should be " ****"
" **  * *"

我不明白为什么它对前 2 个元素是正确的,然后对之后的任何东西都不正确。我已经对其进行了多次跟踪,但一切似乎都应该可以正常工作。

编辑 解决方案:

makeStr :: [Integer] -> String
makeStr [] = ""
makeStr (x:xs)
            | x == 0 = "*" ++ makeStr (map (subtract 1) xs)
            | x /= 0 = " " ++ makeStr (map (subtract 1) (x:xs))

【问题讨论】:

  • 你能写一个函数mergeStars :: String -&gt; String -&gt; String 来获取其中两个星表并生成一个将两者的星组合起来的函数吗?提示:你可能想使用zipWith
  • 我会找到列表的最大值,然后 map 在枚举 [0..maxOfList] 上使用一个检查数字是否在输入列表中的函数,并生成 '*' 或 @987654344 @ 相应地。
  • [2,2] 的输出是什么?对于[3,1]?
  • 看起来s 中的makeStr (x:xs) s 从未使用过。类型签名不能只是makeStr :: [Integer] -&gt; String 而不是makeStr :: [Integer] -&gt; String -&gt; String

标签: haskell functional-programming


【解决方案1】:

可能的解决方案可以遵循这些步骤。

  • 如果输入列表为空,则返回空字符串。
  • 如果输入列表是x:xs,请检查x
    • 如果是x==0,则发出'*',并使用xs 递归,其中每个数字都已递减
    • 如果x/=0,则发出' ',并使用x:xs递归,其中每个数字都已递减

例如

f [1,3]
= ' ' : f [0,2]
= ' ' : '*' : f [1]
= ' ' : '*' : ' ' : f [0]
= ' ' : '*' : ' ' : '*' : f []
= ' ' : '*' : ' ' : '*' : []
= " * *"

上面的内容并不高效。可以提高效率,保留第二个“偏移”整数参数,并增加它而不是减少整个列表。

【讨论】:

  • 你必须在每一步检查每个元素,考虑f [3, 1]
  • @Koterpillar OP 声明“列表将始终是从 0-9 的数字,不断增加,并且没有重复”,所以这不会发生。
  • 抱歉,我没有注意到,只是想对示例中的要求进行逆向工程 :)
  • 啊,我希望我能想到这一点。我真的太复杂了我必须做的事情哈哈,我会用这个解决方案更新我的帖子
【解决方案2】:

@chi 解决方案,但不需要在每个递归步骤中递减列表中的每个元素。

makeStr = f 0

f _ [] = ""
f i (x:xs)
    | x - i == 0 = '*' : f (i+1) xs
    | otherwise  = ' ' : f (i+1) (x:xs)

【讨论】:

  • 我更喜欢f i (x:xs) = replicate (x-i) " " ++ '*' : f (x+1) xs,不需要单步整数累加器
猜你喜欢
  • 2021-12-12
  • 1970-01-01
  • 2011-05-12
  • 1970-01-01
  • 1970-01-01
  • 2011-10-01
相关资源
最近更新 更多