Split a number into its digits with Haskell
Solution 1
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).
Solution 2
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 point free and uses Int, because a digit shouldn't really exceed maxBound :: Int
.
Solution 3
You could also just reuse digits
from Hackage.
Solution 4
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))
Solution 5
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?
Related videos on Youtube
Greg B
I own Backslash Software, a small digital marketing agency. I was head of .NET development at twentysix. I have won a Flash Forward award (in the art category) for my work on 15x15. I am an EPiServer certified developer.
Updated on May 24, 2020Comments
-
Greg B over 3 years
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); }
-
kennytm about 13 years
-
Greg B about 13 years@FUZxxl because I want to work with each digit in turn as a number
-
fuz about 13 yearsSomething like
showNumbers = show >=> return
?
-
-
kennytm about 13 years
-
Greg B about 13 yearsI've added an example to my code as I don't see how div and mod will help me walk over the digits of any arbitrary number. Could you expand on your thoughts please.
-
Roman Gonzalez about 13 years@Greg B this is a haskell source code that does the exact same thing your algorithm does, but using @supercooldave algorithm => pastie.org/1231091
-
muhmuhten about 13 yearsthe
digitToInt
version is probably better anyway, and:[]
was slightly more obvious to me. eh, I'll edit it in. I have no idea where pure is from, so. -
muhmuhten about 9 yearsreread this, this time recognizing
pure
and yes, that would be equivalent. (it is required to be equivalent.) -
MySchizoBuddy almost 9 yearscan you explain what the "period" does between read and return
-
muhmuhten almost 9 yearsfunction composition.
(.) :: (b -> c) -> (a -> b) -> a -> c
-
MySchizoBuddy almost 9 yearsso that digs 001 will be [0,0,1]
-
MySchizoBuddy almost 9 yearsdigits 0123 should be [0,1,2,3]
-
Dave Clarke almost 9 yearsdigs 001 = digs 1 = [1] because 001 = 1.
-
alice kibin about 8 yearsOr in point free style it would be:
toDigits = map (toInteger . digitToInt) . show
-
eatingthenight about 8 yearsJust a reminder that this fails in the case of negative numbers.
-
Isaac over 7 yearsThis answer would be much improved with an explanation
-
Raman Shah over 6 yearsCould you refactor that with an
abs
? -
Tamoghna Chowdhury over 6 yearsThis isn't tail recursion - there's a cons operation in the last branch other than the recursive call.
-
Tamoghna Chowdhury over 6 yearsThis isn't tail recursion - there's a cons operation in the last branch other than the recursive call.
-
Redu about 6 yearsObviously this is the way to do. If you include
import Data.Bool.bool
then you can make it even more sexy likeunfoldr (\x -> bool Nothing (Just (rem x 10, div x 10)) (x > 0))
-
Blank Chisui about 6 years
quotRem
splits of the last digit basically and returns a tuple of the digit and the rest. -
Matthias Braun over 5 yearsVariant that works with negative numbers:
digits d = reverse . unfoldr (\x -> bool (Just $ swap $ divMod x 10) Nothing (x == 0)) $ abs d
. Needed imports:Data.List (unfoldr)
,Data.Tuple (swap)
,Data.Bool (bool)
-
dopamane about 5 yearsI like how this solution uses map versus pattern matching, such idiom!
-
jpmarinier over 4 yearsPerfect solution, except that it is probably best to use divMod, if we are not sure whether the compiler will optimize the common work between div and mod all by itself.
-
Wilco Verhoef almost 3 years@MySchizoBuddy No,
0123
isn't an Integer. If you were to use that literal in your code it would just be interpreted as the value123
or123.0
depending on the type. Try typing just0123
in ghci.