Split a number into its digits with Haskell

0 votes
asked Oct 18, 2010 by greg-b

Given an arbitrary number, how can I process each digit of the number individually?

Edit I've added a basic example of the kind of thing Foo might do.

For example, in C# I might do something like this:

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);
}

13 Answers

0 votes
answered Oct 18, 2010 by dave-clarke

Have you heard of div and mod?

You'll probably want to reverse the list of numbers if you want to treat the most significant digit first. Converting the number into a string is an impaired way of doing things.

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

Generalize into a function:

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

Or in reverse:

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

This treats 0 as having no digits. A simple wrapper function can deal with that special case if you want to.

Note that this solution does not work for negative numbers (the input x must be integral, i.e. a whole number).

0 votes
answered Oct 18, 2010 by daniel

Using the same technique used in your post, you can do:

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

See it in action:

Prelude> digits 123
[1,2,3]

Does that help?

0 votes
answered Oct 18, 2010 by muhmuhten
digits :: Integer -> [Int]
digits = map (read . (:[])) . show

or you can return it into []:

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

or, with Data.Char.digitToInt:

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

the same as Daniel's really, but pointless and uses Int, because a digit shouldn't really exceed maxBound :: Int.

0 votes
answered Oct 19, 2010 by landei

You can use

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

or for reverse order

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

The iterate part generates an infinite list dividing the argument in every step by 10, so 12345 becomes [12345,1234,123,12,1,0,0..]. The takeWhile part takes only the interesting non-null part of the list. Then we reverse (if we want to) and take the last digit of each number of the list.

I used point-free style here, so you can imagine an invisible argument n on both sides of the "equation". However, if you want to write it that way, you have to substitute the top level . by $:

digits n = map(`mod` 10) $ reverse $ takeWhile (> 0) $ iterate (`div`10) n
0 votes
answered Jan 10, 2011 by jon-darkstar

Textbook unfold

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 votes
answered Oct 14, 2011 by hammar

You could also just reuse digits from Hackage.

0 votes
answered Jan 4, 2015 by andrey

Via list comprehension:

import Data.Char

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

output:

> digits 1234567890
[1,2,3,4,5,6,7,8,9,0]
0 votes
answered Jan 6, 2015 by duda-dornelles

For returning a list of [Integer]

import Data.Char
toDigits :: Integer -> [Integer]
toDigits n = map (\x -> toInteger (digitToInt x)) (show n)
0 votes
answered Jan 8, 2015 by granmoe

Here's an improvement on an answer above. This avoids the extra 0 at the beginning ( Examples: [0,1,0] for 10, [0,1] for 1 ). Use pattern matching to handle cases where x < 10 differently:

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

I would have put this in a reply to that answer, but I don't have the needed reputation points :(

0 votes
answered Jan 21, 2015 by mschuett

The accepted answer is great but fails in cases of negative numbers since mod (-1) 10 evaluates to 9. If you would like this to handle negative numbers properly... which may not be the case the following code will allow for it.

digs :: Int -> [Int]
digs 0 = []
digs x
  | x < 0 = digs ((-1) * x)
  | x > 0 = digs (div x 10) ++ [mod x 10]
Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...