scala - List[Int] => Int without String Conversion? -


i came following convert list[int] => try[bigdecimal]:

import scala.util.try  def f(xs: list[int]): try[bigdecimal] =   try { xs.mkstring.toint }.map ( bigdecimal(_) ) 

example:

scala> f(list(1,2,3,4)) res4: scala.util.try[bigdecimal] = success(1234)  scala> f(list(1,2,3,55555)) res5: scala.util.try[bigdecimal] = success(12355555) 

is there way write function without resorting string conversion step?

not pretty, , i'm not convinced it's more efficient. here's basic outline.

val pwrs:stream[bigint] = 10 #:: pwrs.map(_ * 10) list(1,2,3,55555).foldleft(0:bigint)((p,i) => pwrs.find(_ > i).get * p + i) 

here little more fleshed out error handling.

import scala.util.try def f(xs: list[int]): try[bigdecimal] = try {    lazy val pwrs: stream[bigdecimal] = 10 #:: pwrs.map(_ * 10)   xs.foldleft(0: bigdecimal) {     case (acc, i) if >= 0 => pwrs.find(_ > i).get * acc +     case _ => throw new error("bad")   } } 

update

just giggles, thought i'd plug code rex kerr's handy benchmarking/profiling tool, thyme.

the code

import scala.util.try  def fstring(xs: list[int]): try[bigint] = try { bigint(xs.mkstring) }  def fstream(xs: list[int]): try[bigint] = try {   lazy val pwrs: stream[bigint] = 10 #:: pwrs.map(_ * 10)   xs.foldleft(0: bigint) {     case (acc, i) if >= 0 => pwrs.find(_ > i).get * acc +     case _ => throw new error("bad")   } }  def flog10(xs: list[int]): try[bigint] = try {   xs.foldleft(0: bigint) {     case (acc, i) if >= 0 =>       math.pow(10, math.ceil(math.log10(i))).toint * acc +     case _ => throw new error("bad")   } } 

fstring() slight simplification of kevin's original question. fstream() proposed non-string implementation. flog10 same alexey's suggested enhancement.

you'll note i'm using bigint instead of bigdecimal. found both non-string methods encountered bug somewhere around 37th digit of result. kind of rounding error or something, there no problem bigint that's used.

test setup

// create list of 40 ints , check contents val lst = list.fill(40)(util.random.nextint(20000)) lst.min              // 5 lst.max              // 19858 lst.mkstring.length  // 170  val th = ichi.bench.thyme.warmed(verbose = print) th.pbenchwarm(th.warm(fstring(lst)), title="fstring") th.pbenchwarm(th.warm(fstream(lst)), title="fstream") th.pbenchwarm(th.warm(flog10(lst)),  title="flog10") 

results

benchmark fstring (20 calls in 345.6 ms) time: 4.015 95% ci 3.957 - 4.073 (n=19) garbage: 109.9 ns (n=2 sweeps measured)

benchmark fstream (20 calls in 305.6 ms) time: 7.118 95% ci 7.024 - 7.213 (n=19) garbage: 293.0 ns (n=3 sweeps measured)

benchmark flog10 (20 calls in 382.8 ms) time: 9.205 95% ci 9.187 - 9.222 (n=17) garbage: 73.24 ns (n=2 sweeps measured)

so right efficiency of non-string algorithm. oddly, using math._ avoid stream creation doesn't appear better. didn't expect that.

takeaway

number-to-string , string-to-number transitions reasonably efficient.


Comments