首页 文章

Haskell反向整数与递归

提问于
浏览
1

我想用递归来反转Haskell中的Integer . 我有一个小问题 .

这是代码:

reverseInt :: Integer -> Integer
reverseInt n
|  n>0 = (mod n 10)*10 + reverseInt(div n 10)
|  otherwise = 0

例345

我用作输入345,我想输出543

在我的程序中它会做....

reverseInt 345
345>0
mod 345 10 -> 5
reverseInt 34
34
34>0
mod 34 10 -> 4
reverseInt 3
3>0
mod 3 10 -> 3
reverseInt 0
0=0 (ends)

最后它返回它们的总和... 5 4 3 = 12 .

所以我希望每一次在它们总结之前,将多个总和* 10 . 所以它会...

5
5*10 + 4
54*10 + 3
543

6 回答

  • 1

    这是一个相对简单的:

    reverseInt :: Int -> Int
    reverseInt 0 = 0
    reverseInt n = firstDigit + 10 * (reverseInt $ n - firstDigit * 10^place)
      where
        n' = fromIntegral n
        place = (floor . logBase 10) n'
        firstDigit = n `div` 10^place
    

    基本上,

    • 你拿输入整数的 logBase 10 来给你它在哪个地方(10s,100s,1000s ......)

    • 因为前面的计算给出了一个浮点数,我们不需要小数,我们使用 floor 函数来截断小数后面的所有内容 .

    • 我们通过 n 'div' 10^place 确定数字的第一个数字 . 例如,如果我们有543,我们会找到2的位置,所以firstDigit = 543/100 = 5(整数除法)

    • 我们使用此值,并将其添加到10 *与整数的'rest'相反,在本例中为43 .

    编辑:也许更简洁易懂的版本可能是:

    reverseInt :: Int -> Int
    reverseInt 0 = 0
    reverseInt n = mod n 10 * 10^place + reverseInt (div n 10)
      where
        n' = fromIntegral n
        place = (floor . logBase 10) n'
    

    这一次,我们不是通过第一个数字递归,而是通过最后一个数字递归并使用地方给它正确的零数 .

  • 4
    reverseInt :: Integer -> Integer
    reverseInt n = snd $ rev n
                   where
                     rev x
                       |  x>0 = let (a,b) = rev(div x 10)
                                in ((a*10), (mod x 10)*a + b)
                       |  otherwise = (1,0)
    

    读者留给读者:)

  • 0

    我不知道在你的第3行中你应该多少次乘以 (mod n 10) 的方便方法 . 我更喜欢 unfoldr 的解决方案:

    import Data.List
    listify = unfoldr (\ x -> case x of
                                 _ | x <= 0 -> Nothing
                                 _          -> Just(mod x 10, div x 10) )
    
    reverse_n n = foldl (\ acc x -> acc*10+x) 0 (listify n)
    

    listify 函数中,我们以相反的顺序从整数生成数字列表,然后我们构建结果简单折叠列表 .

  • 0

    或者只是将其转换为字符串,将其反转并将其转换回整数:

    reverseInt :: Integer -> Integer
     reverseInt = read . reverse . show
    
  • 1

    更多(不一定基于递归)答案非常好!

    reverseInt 0 = 0
    reverseInt x = foldl (\x y -> 10*x + y) 0 $ numToList x
      where
        numToList x = if x == 0 then [] else (x `rem` 10) : numToList (x `div` 10)
    

    这基本上是两个函数的串联:numToList(将给定的整数转换为列表123 - > [1,2,3])和listToNum(执行相反的操作) .

    numToList函数通过重复获取数字的最低单位(使用 rem ,Haskell的余数函数),然后将其删除(使用 div ,Haskell的整数除法函数)来工作 . 一旦数字为0,将返回空列表,并将结果连接到最终列表中 . 请记住,此列表的顺序相反!

    listToNum函数(未见)是一段非常性感的代码:

    foldl (\x y -> 10*x + y) 0 xs
    

    这从左侧开始向右移动,将每一步的当前值乘以10,然后将下一个数字加到它上面 .

    我知道已经给出了答案,但看到替代解决方案总是很好:)

  • 0

    第一个函数是递归的,将整数转换为列表 . 它最初是倒车,但重新转换功能更容易扭转,所以我把它从第一个中取出 . 这些功能可以单独运行 . 第一个输出一对元组 . 第二个采用元组对 . 第二个不是递归,也不是必须的 .

    di 0 ls = (ls,sum ls);  di n ls = di nn $ d:ls  where (nn,d) = divMod n 10
    di 3456789 []
    

    ([3,4,5,6,7,8,9],42)

    rec (ls,n) = (sum [y*(10^x)|(x,y) <- zip [0..] ls ],n)
    

    同时运行为

    rec $ di 3456789 []
    

    (9876543,42)

相关问题