patternMinor
Alien Numbers - how Scala-ish is my solution?
Viewed 0 times
numbersscalaishalienhowsolution
Problem
I'm trying to solve an old GCJ. It's a very simple puzzle, but I'm trying to sharpen my Scala-fu.
Basically, you're getting a list of triple
A numeral system is simply a string of all possible digits, in ascending order. The decimal numeral system is represented by
For example:
Here's how I implemented it in Scala:
Basically, you're getting a list of triple
number srcLanguage dstLanguage, where number is an integer given in the numeral system of srcLanguage. You should translate it to the numeral system of dstLanguage.A numeral system is simply a string of all possible digits, in ascending order. The decimal numeral system is represented by
0123456789, the binary numeral system is 01, and the hexadecimal one 0123456789ABCDEF.For example:
3 0123456789 01 -> 11
3 0123 AB -> BBHere's how I implemented it in Scala:
case class Langs(num:String,srcLang:String,dstLang:String)
object Langs {def fromLine(line:String):Langs = {
val ar = line.split(" ");return Langs(ar(0),ar(1),ar(2))}}
object Translate {
def lang2int(lang:String,num:String):Long = {
var b = BigDecimal(0)
val dmap = (lang.toList.zipWithIndex).toMap
val digitsList = num map dmap
val valueList = digitsList.reverse.zipWithIndex map (
x => x._1 -> math.pow(dmap.size,x._2))
return valueList.map(x=>x._1*x._2).sum.toLong
}
def int2lang(lang:String,_num:Long):String = {
var num = _num
val dmap = (lang zip (0.toLong to lang.size)).map(_.swap).toMap
val sb = StringBuilder.newBuilder
while (num > 0) {
sb.append(dmap(num % dmap.size))
num = num/dmap.size
}
sb.reverse.toString
}
def lang2lang(l:Langs):String = int2lang(l.dstLang,lang2int(l.srcLang,l.num))
}
object mymain {
def main(args : Array[String]) : Unit = {
val s = "A-large-practice"
val basef = new java.io.FileInputStream("~/Downloads/"+s+".in")
val f = new java.util.Scanner(basef)
val out = new java.io.FileWriter(s+".out")
val n = f.nextInt
f.nextLine
for (i <- 1 to n) {
val nl = f.nextLine
val l = Langs.fromLine(nl)
out.write("Case #"+i+": "+Translate.lang2lang(l)+"\n")
}
out.close
}
}Solution
- You should definitely use
scala.io.Sourcefor File-IO
- I wouldn't consider String splitting a responsibility of a general-purpose class. This should be done in the main loop
- For tuples you can write map{ case (one,two) => ... }, which is often clearer than using x._1 and x._2
- You don't need to write return if it's the last statement of the block
- You can use pattern matching when defining vals:
val Array(x, y, z) = line.split(" ")
Here is my attempt:
case class Langs(num:String, srcLang:String, dstLang:String)
object Langs {
def fromLine(line:String):Langs = {
val Array(num, srcLang, dstLang) = line.split(" ")
Langs(num, srcLang, dstLang)
}
}
object Translate {
def lang2int(lang:String,num:String):Long = {
val dmap = lang.toList.zipWithIndex.toMap
val digitsList = num map dmap
val valueList = digitsList.reverse.zipWithIndex map {
case (one, two) => one -> math.pow(dmap.size, two)}
valueList.map{case (one,two) => one*two}.sum.toLong
}
def int2lang(lang:String, num:Long):String = {
val dmap = (0.toLong to lang.size zip lang).toMap
Iterator.iterate(num)( _/dmap.size).takeWhile(_ > 0).map(n =>
dmap(n % dmap.size)).mkString.reverse
}
def lang2lang(l:Langs):String = int2lang(l.dstLang,lang2int(l.srcLang,l.num))
}Eliminating the while loop isn't that straight-forward, maybe someone else has an idea how to avoid that Iterator train-wreck.
[Edit]
I asked in another forum for a better solution for
int2lang, and got this answer:def int2lang(lang: String, num: Long): String = {
val dmap = (0L to lang.size) zip lang toMap
val size = dmap.size
def loop(num: Long, l: List[Char]): List[Char] =
if (num == 0) l else loop(num/size, dmap(num%size) :: l)
loop(num, Nil).mkString
}The nice thing about this is that the
reverse is gone.Code Snippets
case class Langs(num:String, srcLang:String, dstLang:String)
object Langs {
def fromLine(line:String):Langs = {
val Array(num, srcLang, dstLang) = line.split(" ")
Langs(num, srcLang, dstLang)
}
}
object Translate {
def lang2int(lang:String,num:String):Long = {
val dmap = lang.toList.zipWithIndex.toMap
val digitsList = num map dmap
val valueList = digitsList.reverse.zipWithIndex map {
case (one, two) => one -> math.pow(dmap.size, two)}
valueList.map{case (one,two) => one*two}.sum.toLong
}
def int2lang(lang:String, num:Long):String = {
val dmap = (0.toLong to lang.size zip lang).toMap
Iterator.iterate(num)( _/dmap.size).takeWhile(_ > 0).map(n =>
dmap(n % dmap.size)).mkString.reverse
}
def lang2lang(l:Langs):String = int2lang(l.dstLang,lang2int(l.srcLang,l.num))
}def int2lang(lang: String, num: Long): String = {
val dmap = (0L to lang.size) zip lang toMap
val size = dmap.size
def loop(num: Long, l: List[Char]): List[Char] =
if (num == 0) l else loop(num/size, dmap(num%size) :: l)
loop(num, Nil).mkString
}Context
StackExchange Code Review Q#2502, answer score: 3
Revisions (0)
No revisions yet.