2010-10-18 98 views
28

给定一个任意数字,我如何分别处理每个数字的数字?用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); 
} 
+1

相关:http://stackoverflow.com/questions/2838727/how-do-i-get-the-sums-of-the-digits-of-a-large-number-in-haskell – kennytm 2010-10-18 21:01:24

+1

你为什么不使用show? – fuz 2010-10-19 05:48:55

+0

@FUZxxl,因为我想依次将每个数字作为数字 – 2010-10-20 07:39:32

回答

70

你有没有听说过的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必须是整数,即整数)。

+0

小心给我举个例子吗? – 2010-10-18 21:01:22

+2

[quotRem](http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/Prelude.html#v%3AquotRem)。 – kennytm 2010-10-18 21:02:34

+0

我已经向我的代码中添加了一个示例,因为我没有看到div和mod如何帮助我遍历任意数字的数字。请你扩展你的想法。 – 2010-10-18 21:05:50

10

使用在您的文章中使用相同的技术,你可以这样做:

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

看到它在行动:

Prelude> digits 123 
[1,2,3] 

这是否帮助?

+6

'digits = map(read。(:[]))。显示' – muhmuhten 2010-10-18 22:47:32

+0

数字0123应该是[0,1,2,3] – MySchizoBuddy 2014-11-24 21:06:55

16
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 

一样丹尼尔真的,但毫无意义,并使用诠释,因为一个数字不应该超过maxBound :: Int

+0

也许(digits = map(read。return)。show)?或(读纯粹).. – 2010-10-19 20:36:05

+1

'digitToInt'版本可能更好,而':[]'对我来说稍微更明显。呃,我会编辑它。我不知道从哪里来的纯粹,所以。 – muhmuhten 2010-10-19 22:00:31

+0

重读了这一点,这一次认识到“纯”和是的,这是相当的。 (需要等价。) – muhmuhten 2014-08-18 00:27:08

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部分仅使用列表中有趣的非空部分。然后我们反转(如果我们想要)并拿出列表中每个数字的最后一位数字。

我在这里使用了无点风格,所以你可以想象在“等式”两边有一个看不见的参数。但是,如果你想要把它写这样一来,你必须$替代顶层.

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

教科书展开

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

显然这是要做的。如果你包含'import Data.Bool.bool',那么你可以使它更像'unfoldr(\ x - > bool Nothing(Just(rem x 10,div x 10))(x> 0)'' – Redu 2017-10-12 15:34:37

0

回访[整数]列表

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

在点自由风格它将是: 'toDigits =地图(toInteger。digitToInt)。显示' – kibin 2015-08-16 17:20:50

1

接受的答案是伟大的,但未能在负数的情况下,因为mod (-1) 10计算结果为9.如果你想这可以正确处理负数......下面的代码可能不适用于此情况。

digs :: Int -> [Int] 
digs 0 = [] 
digs x 
    | x < 0 = digs ((-1) * x) 
    | x > 0 = digs (div x 10) ++ [mod x 10] 
+0

你可以重构一个'abs'吗? – 2017-06-13 12:51:57

0

通过列表理解:

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] 
1

下面是关于上述答案的改善。这避免了开始处的额外0(例如:[0,1,0]为10,[0,1]为1)。使用模式匹配来处理案件,其中x < 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] 

我会到这个问题的答案的答复都提出这一点,但我没有必要的声誉分:(

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

这个答案将大大改善,并解释 – 2016-05-01 19:43:46

+0

基本上是“最后一位数”的“拆分”拆分,并返回数字和其余部分的元组。 – 2017-11-02 15:28:08

0

我试着用尾递归

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

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

这不是尾递归 - 在递归调用之外的最后一个分支中有一个cons操作。 – 2017-06-27 18:04:13

+0

这不是尾递归 - 除了递归调用之外,最后一个分支中有一个cons操作。 – 2017-06-27 18:04:23

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"