使用Haskell将数字拆分为数字

时间:2010-10-18 20:50:01

标签: haskell

给定一个任意数字,我如何单独处理数字的每个数字?

修改 我添加了Foo可能会做的事情的基本示例。

例如,在C#中,我可能会这样做:

static void Main(string[] args)
{
    int number = 1234567890;
    string numberAsString = number.ToString();

    foreach(char x in numberAsString)
    {
        string y = x.ToString();
        int z = int.Parse(y);
        Foo(z);
    }
}

void Foo(int n)
{
    Console.WriteLine(n*n);
}

17 个答案:

答案 0 :(得分:78)

您听说过div and mod吗?

如果您想先处理最重要的数字,您可能想要反转数字列表。将数字转换为字符串是一种受损的做事方式。

135 `div` 10 = 13
135 `mod` 10 = 5

概括成一个函数:

digs :: Integral x => x -> [x]
digs 0 = []
digs x = digs (x `div` 10) ++ [x `mod` 10]

或反过来:

digs :: Integral x => x -> [x]
digs 0 = []
digs x = x `mod` 10 : digs (x `div` 10)

这会将0视为没有数字。如果你愿意,一个简单的包装函数可以处理这种特殊情况。

请注意,此解决方案不适用于负数(输入x必须是整数,即整数)。

答案 1 :(得分:19)

digits :: Integer -> [Int]
digits = map (read . (:[])) . show

或者您可以将其返回[]

digits :: Integer -> [Int]
digits = map (read . return) . show

或者,使用Data.Char.digitToInt:

digits :: Integer -> [Int]
digits = map digitToInt . show

和丹尼尔一样,但是点免费使用Int,因为数字不应该超过maxBound :: Int

答案 2 :(得分:13)

你也可以从Hackage中重用digits

答案 3 :(得分:12)

使用帖子中使用的相同技巧,您可以:

digits :: Integer -> [Int]
digits n = map (\x -> read [x] :: Int) (show n)

看到它的实际效果:

Prelude> digits 123
[1,2,3]

这有帮助吗?

答案 4 :(得分:10)

教科书展开

import qualified Data.List as L
digits = reverse . L.unfoldr (\x -> if x == 0 then Nothing else Just (mod x 10, div x 10))

答案 5 :(得分:9)

您可以使用

digits = map (`mod` 10) . reverse . takeWhile (> 0) . iterate (`div` 10)

或反向订单

rev_digits = map (`mod` 10) . takeWhile (> 0) . iterate (`div` 10)

迭代部分生成一个无限列表,将每个步骤中的参数除以10,因此12345变为[12345,1234,123,12,1,0,0 ..]。 takeWhile部分仅采用列表中有趣的非null部分。然后我们反转(如果我们想)并取每个数字列表的最后一位数。

我在这里使用了无点样式,因此您可以想象“等式”两侧的无形参数n。但是,如果您想以这种方式编写,则必须用.替换顶级$

digits n = map(`mod` 10) $ reverse $ takeWhile (> 0) $ iterate (`div`10) n

答案 6 :(得分:2)

通过列表理解:

import Data.Char

digits :: Integer -> [Integer]
digits n = [toInteger (digitToInt x) | x <- show n]

输出:

> digits 1234567890
[1,2,3,4,5,6,7,8,9,0]

答案 7 :(得分:2)

ApplicativePointfreeOrigami。整齐。

享受:

import Data.List                                                                
import Data.Tuple                                                               
import Data.Bool                                                                
import Control.Applicative 

digits = unfoldr $ liftA2 (bool Nothing) (Just . swap . (`divMod` 10)) (> 0) 

答案 8 :(得分:2)

以上是对上述答案的改进。这避免了开头的额外0(例如:[0,1,0]为10,[0,1]为1)。使用模式匹配来处理x <1的情况。 10不同:

toDigits :: Integer -> [Integer] -- 12 -> [1,2], 0 -> [0], 10 -> [1,0]
toDigits x
    | x < 10 = [x]
    | otherwise = toDigits (div x 10) ++ [mod x 10]

我会回答这个问题,但我没有所需的声誉点:(

答案 9 :(得分:1)

接受的答案很好但是在负数的情况下失败,因为TypeError Traceback (most recent call last) <ipython-input-81-e74a15accb5b> in <module>() 5 print 'The first 5 tweets for \"{}\":\n'.format(keywords[0]) 6 for txt in k1_tweets_processed[0:5]: ----> 7 print txt['text'] 8 print 9 TypeError: list indices must be integers, not str 评估为9.如果你希望这个正确地处理负数...可能不是这种情况下面的代码将允许它

mod (-1) 10

答案 10 :(得分:1)

返回[Integer]列表

import Data.Char
toDigits :: Integer -> [Integer]
toDigits n = map (\x -> toInteger (digitToInt x)) (show n)

答案 11 :(得分:1)

我懒于编写我的自定义函数,所以我用它搜索了一下,令我感到惊讶的是,该网站上的答案都没有提供真正好的解决方案-高性能和类型安全。所以就在这里,也许有人想使用它。基本上:

  1. 这是类型安全的-它返回类型检查的Word8数字非空列表(上述所有解决方案都返回数字列表,但是我们不能正确使用[]吗?)
  2. 这是一个性能优化的应用程序,具有尾部调用优化功能,快速串联功能,并且无需对最终值进行任何反转。
  3. 它使用特殊的分配语法,该语法与-XStrict关联,允许Haskell进行严格性分析并优化内部循环。

享受:

{-# LANGUAGE Strict #-}

digits :: Integral a => a -> NonEmpty Word8
digits = go [] where
    go s x = loop (head :| s) tail where
        head = fromIntegral (x `mod` 10)
        tail = x `div` 10
    loop s@(r :| rs) = \case
        0 -> s
        x -> go (r : rs) x

答案 12 :(得分:1)

我一直在遵循以下步骤(基于this comment):

  1. 将整数转换为字符串。
  2. 遍历字符串 逐个字符。
  3. 将每个字符转换回整数, 并将其附加到列表末尾。

toDigits :: Integer -> [Integer]
toDigits a = [(read([m])::Integer) | m<-show(a)]

main = print(toDigits(1234))

答案 13 :(得分:0)

接受的答案是正确的,只是当输入为0时它将输出一个空列表,但我相信输入为零时输出应为[0]

当输入为负时,我不认为它处理的情况。下面是我的实现,它解决了上述两个问题。

toDigits :: Integer -> [Integer]
toDigits n
 | n >=0 && n < 10 = [n]
 | n >= 10 = toDigits (n`div`10) ++ [n`mod`10]
 | otherwise = error "make sure your input is greater than 0" 

答案 14 :(得分:0)

我想在此页面上完善Dave Clarke的答案。归结为在数字上使用divmod并将其结果添加到列表中,只是这一次它不会出现反转,也不会求助于++(连接速度较慢) )。

toDigits :: Integer -> [Integer]

toDigits n
  | n <= 0    = []
  | otherwise = numToDigits (n `mod` 10) (n `div` 10) []
    where
      numToDigits a 0 l = (a:l)
      numToDigits a b l = numToDigits (b `mod` 10) (b `div` 10) (a:l)

该程序是UPenn CIS 194课程中一个问题的解决方案,可以在here上使用。您将数字相除,以整数形式查找结果,其余部分以另一个形式查找。您将它们传递给第三个参数为空列表的函数。如果除法的结果为0,则其余部分将添加到列表中。如果它是另一个数字,则将再次调用该函数。其余的将按顺序添加到最后。

注意:这是用于数字的,这意味着左边的零不会计数,这将允许您使用其数字进行进一步的操作。

答案 15 :(得分:-1)

我试图继续使用尾递归

toDigits :: Integer -> [Integer]
toDigits x = reverse $ toDigitsRev x

toDigitsRev :: Integer -> [Integer]
toDigitsRev x
    | x <= 0 = []
    | otherwise = x `rem` 10 : toDigitsRev (x `quot` 10)

答案 16 :(得分:-2)

digits = reverse . unfoldr go
  where go = uncurry (*>) . (&&&) (guard . (>0)) (Just . swap . (`quotRem` 10))