Split Int into digits

509 views
Skip to first unread message

imrichardcole

unread,
Nov 21, 2011, 11:01:17 AM11/21/11
to scala-user
Hi,

I'm looking to split an Int into a List of digits, i.e 1234 becomes
List(1,2,3,4).

This seems to work but feels a bit long winded (mainly the toString
bit):

scala> 1234.toString.map(_.asDigit).toList
res3: List[Int] = List(1, 2, 3, 4)

Is there a better way to do this?

Richard

Nils Kilden-Pedersen

unread,
Nov 21, 2011, 11:18:07 AM11/21/11
to imrichardcole, scala-user
On Mon, Nov 21, 2011 at 10:01 AM, imrichardcole <richc...@googlemail.com> wrote:
Is there a better way to do this?

Define better.

Alec Zorab

unread,
Nov 21, 2011, 11:21:30 AM11/21/11
to Nils Kilden-Pedersen, imrichardcole, scala-user
you can do it by recursively taking the modulo and divisor, but it's
longer and may or may not be any faster

imrichardcole

unread,
Nov 21, 2011, 11:28:34 AM11/21/11
to scala-user
I guess the stage I was looking to remove was converting to a String,
but it appears that maybe this is the quickest, most concise approach.

Thanks

Richard

Aleksey Nikiforov

unread,
Nov 21, 2011, 11:52:48 AM11/21/11
to imrichardcole, scala-user
While loops work well for these things:

def digits(n: Int) = { var l = List[Int](); var i = n; while (i != 0) { l ::= i % 10; i /= 10 }; l }
println(digits(1234).mkString(", "))

Josh Suereth

unread,
Nov 21, 2011, 1:15:25 PM11/21/11
to Aleksey Nikiforov, imrichardcole, scala-user
So do recursive functions:

// Assumes positive integers
def digits(n: Int): Seq[Int] = n match {
  case 0 => Vector.empty
  case _ =>  digits(n / 10) :+ (x % 10)
}

Note: The above does *not* trampoline, so it could blow the stack.  You can unwind that with a helper function:

// Assumes positive integers
def digits(n: Int): Seq[Int] = {
  def digitHelper(cur: Int, result: Seq[Int]): Seq[Int] = cur match {
    case 0 => result
    case _ =>  digitHelper(n/10,  (x % 10) +: result)
  }
  digitHelper(n, Vector.empty)

Seth Tisue

unread,
Nov 21, 2011, 1:55:20 PM11/21/11
to scala-user
On Mon, Nov 21, 2011 at 1:15 PM, Josh Suereth <joshua....@gmail.com> wrote:
> So do recursive functions: [...]

And to complete the hat trick of implementation styles:

def unfold[T1,T2](x: T1)(fn: T1 => Option[(T2, T1)]): Stream[T2] =
fn(x) match {
case None => Stream()
case Some((result, next)) => result #:: unfold(next)(fn)
}

def digits(n: Int) =
unfold(n)(n => if (n == 0) None else Some((n % 10, n / 10)))
.toList.reverse

--
Seth Tisue | Northwestern University | http://tisue.net
lead developer, NetLogo: http://ccl.northwestern.edu/netlogo/

Alec Zorab

unread,
Nov 21, 2011, 2:09:52 PM11/21/11
to Seth Tisue, scala-user
... I like the toString solution

Doug Tangren

unread,
Nov 21, 2011, 6:31:05 PM11/21/11
to Alec Zorab, Seth Tisue, scala-user
Interesting timing. I had to come up with a solution to a similar problem a week or so ago for a local hacking meetup group [1].  I submitted the scala solution to the problem. I just fell back on the toString/asDigit technique. It's ends up being a lot less typing which is not a bad thing.

[1]: https://github.com/hackandtell/wiki/wiki/Round-13

Josh Suereth

unread,
Nov 21, 2011, 7:29:29 PM11/21/11
to Seth Tisue, scala-user

Nice... but this could still blow up the stack iirc.

Doug Tangren

unread,
Nov 21, 2011, 7:35:22 PM11/21/11
to Josh Suereth, Seth Tisue, scala-user
On Mon, Nov 21, 2011 at 7:29 PM, Josh Suereth <joshua....@gmail.com> wrote:

Nice... but this could still blow up the stack iirc.


Oh, I tried a few things. One of which resulted in 


:)

Stefan Wagner

unread,
Nov 22, 2011, 12:49:52 AM11/22/11
to scala...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Am 21.11.2011 19:15, schrieb Josh Suereth:
> So do recursive functions:
>
> // Assumes positive integers
> def digits(n: Int): Seq[Int] = n match {
> case 0 => Vector.empty
> case _ => digits(n / 10) :+ (x % 10)
> }
>
> Note: The above does *not* trampoline, so it could blow the stack. You can
> unwind that with a helper function:

Blow the stack with an Int? Maybe with some BigInt, but not with Int or
Long, or am I missing something?

- --

Tsch���--->...Stefan
- ---------------------------
Don't visit my homepage at:
http://home.arcor-online.net/hirnstrom
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk7LOAAACgkQQeATqGpDnRpowQCeOqN+f1QPirZjoCa0dFffDWd9
si4AnAnRdpx5MJ7XSrsxGKdkDGfcSl9E
=d8mE
-----END PGP SIGNATURE-----

Bernd Johannes

unread,
Nov 22, 2011, 1:00:14 AM11/22/11
to scala-user, Doug Tangren

I think that's from the REPL not from the compiler - but I didn't grep the
sources :-)

Greetings
Bernd

Doug Tangren

unread,
Nov 22, 2011, 1:02:23 AM11/22/11
to Bernd Johannes, scala-user
Yep, sry. That was me tinkering with the repl. 

Vlad Patryshev

unread,
Nov 22, 2011, 2:45:45 AM11/22/11
to imrichardcole, scala-user
def split(n: Int) = if (n == 0) List(0) else {
    (Stream.iterate(n)(_/10)takeWhile(_!=0)map(_%10)toList) reverse
}


Thanks,
-Vlad

Richard Cole

unread,
Nov 22, 2011, 4:01:20 AM11/22/11
to Vlad Patryshev, scala-user
Thanks for all the suggestions. Very interesting how something seemingly simple has so many interesting solutions

Rich

Sent from my iPhone

martin odersky

unread,
Nov 22, 2011, 1:12:56 PM11/22/11
to Doug Tangren, Josh Suereth, Seth Tisue, scala-user
That's what you get for a ctrl-c these days :-)

Cheers

 -- Martin

Stefan Wagner

unread,
Nov 23, 2011, 10:32:47 AM11/23/11
to scala...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Am 21.11.2011 17:01, schrieb imrichardcole:
> Hi,
>
> I'm looking to split an Int into a List of digits, i.e 1234 becomes
> List(1,2,3,4).

Here is a comparision of some algorithms, mentioned in this Thread.
- From 1=40 000 to 10=400 000 Ints converted:

0 whileDigits toStrDigits matchDigits unfoldDigits iterateDigits
carryDigits
1 0.146 0.336 0.753 0.327 0.51 0.04
2 0.201 0.614 1.424 0.547 0.894 0.068
3 0.276 0.973 2.239 0.927 1.359 0.149
4 0.347 1.509 2.781 1.335 1.802 0.118
5 0.427 1.801 3.419 1.623 2.277 0.258
6 0.48 1.563 4.221 2.132 2.834 0.23
7 0.595 1.874 5.072 2.101 3.729 0.849
8 0.718 2.903 8.226 2.936 4.641 1.144
9 0.694 4.838 9.073 4.754 5.184 0.996
10 1.173 5.911 9.161 4.223 5.651 0.772

carryDigits wasn't mentioned so far:


@tailrec
def carryDigits (n: Int, carry: List[Int]): List [Int] =
if (n < 10) n :: carry
else carryDigits (n/10, (n % 10) :: carry)
def digits6 (i: I) : O = i.map (n => carryDigits (n, List ()))

The whole benchmark source in the comments of
> https://gist.github.com/1372818#comments

Using big Ints up to MaxValue does not make much difference, compared to
Ints of size up to 9999.


- --

Tsch���--->...Stefan
- ---------------------------
Don't visit my homepage at:
http://home.arcor-online.net/hirnstrom
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk7NEh8ACgkQQeATqGpDnRqbsQCdEvglBKJispoCwmzEup/h/IIN
gWcAnAsvvziRmxuKHEpsX3YG8DWzZF/V
=2+1q
-----END PGP SIGNATURE-----

Reply all
Reply to author
Forward
0 new messages