Чужеродные цифры - как скала-ишь мое решение?


Я пытаюсь решить старый транспорт. Это очень простая головоломка, но я пытаюсь заострить моя скала-фу.

В основном, вы получаете список трехместный номер srcLanguage dstLanguage, где число - целое число дано в системе счисления из srcLanguage. Вы должны перевести его в цифровой системе dstLanguage.

Система счисления-это просто строка из всех возможных цифр в порядке возрастания. В десятичной системе счисления представляется 0123456789двоичная система счисления-это 01, а шестнадцатеричное один 0123456789ABCDEF.

Например:

3 0123456789 01 -> 11
3 0123       AB -> BB

Вот как я реализовал это в 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
  }
}


Комментарии
3 ответа


  • Вы должны определенно использовать скала.Ио.Источник для файл-ИО

  • Я не считаю строки разделения ответственности класс общего назначения. Это должно быть сделано в главном цикле

  • Для кортежей вы можете написать карту{ случай (один,два) => ... }, который часто яснее, чем с помощью X._1 и X._2

  • Вам не нужно писать возврат, если это последнее утверждение блока

  • Вы можете использовать сопоставление с образцом при определении вальс: вал массива(х, у, Z) = линия.сплит(" ")

Вот моя попытка:

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

Исключения пока петля не так прямолинейно, может еще кто-нибудь есть идея, как избежать, что итератор поезд-развалюху.

[Править]

Я спросил в другом форуме лучшее решение для int2lang, и получил такой ответ:

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
}

Хорошая вещь об этом состоит в том, что обратного нет.

3
ответ дан 20 мая 2011 в 12:05 Источник Поделиться

Мои предложения.


  • Воспользоваться тем, что сл[Т] является функцией int => т.

  • Использовать рекурсию.

Пример:

def int2lang(lang:String, num:Long): String = 
if (num == 0l) ""
else int2lang(lang, num / lang.size) + lang(num % lang.size toInt)

Если вы хотите воспользоваться хвостовую рекурсию, используют гидроаккумулятор:

@scala.annotation.tailrec
def int2lang(lang:String, num:Long, acc: String = ""): String =
if (num == 0l) acc
else int2lang(lang, num / lang.size, lang(num % lang.size toInt) + acc)

Но это неоптимальное относительно конкатенации строк, так что вы могли бы сделать это:

@scala.annotation.tailrec
def int2lang(lang:String, num:Long, acc: List[Char] = Nil): String =
if (num == 0l) acc.mkString
else int2lang(lang, num / lang.size, lang(num % lang.size toInt) :: acc)

Если вам не нравится рекурсия (и хвостовой рекурсии это очень эффективно), использовать универсальную разворачиваться, а не изобретать его:

def unfoldLeft[A, B](seed: B)(f: B => Option[(B, A)]) = {
def loop(seed: B)(ls: List[A]): List[A] = f(seed) match {
case Some((b, a)) => loop(b)(a :: ls)
case None => ls
}

loop(seed)(Nil)
}

def int2lang(lang: String, num: Long) = unfoldLeft(num) { n =>
if (n == 0) None
else Some((n / lang.size, lang(n % lang.size toInt)))
}.mkString

Если вы развернетесь, чтобы получить Лэнг, сложить, чтобы получить инт:

def lang2int(lang: String, num: String) = {
val lmap = lang.zipWithIndex.toMap
num.foldLeft(0l) { case (acc, digit) => acc * lang.size + lmap(digit) }
}

Обратите внимание, что я использую карту здесь, потому что я хочу Т => Инт. Но так как мы сложены, что было развернулась, посмотрим рекурсии обратное:

def lang2int(lang: String, num: String) = {
val lmap = lang.zipWithIndex.toMap
def recurse(n: String, acc: Long): Long =
if (n.isEmpty) acc
else recurse(n substring 1, acc * lang.size + lmap(n(0)))
recurse(num, 0l)
}

Так самое интересное, давайте посмотрим остальное. Я предпочитаю в свою очередь, в то время как петли в итераторы, если важна производительность. Так:

for (i <- 1 to n) {
val nl = f.nextLine
val l = Langs.fromLine(nl)
out.write("Case #"+i+": "+Translate.lang2lang(l)+"\n")
}

становится

val lines = Iterator continually f.nextLine
for ((l, i) <- lines map Langs.fromLine zipWithIndex)
out.write("Case #"+(i+1)+": "+Translate.lang2lang(l)+"\n")

Я могу переместить карту Лэнг.номерстроки показывает итератору, делая это:

val ns = Iterator continually f.nextLine map Langs.fromLine

или даже

val ns = Iterator continually (Langs fromLine f.nextLine)

И если мне нужны эти цифры более чем одного использования, сделать его трансляцию , а не итератор. Конечно, еще одной альтернативой могло бы быть использование источника.Ио, но это только для легких вещей, в любом случае.

Наконец, не используйте возвращения. А возвращение - это исключение из рода-это обозначает, что функция будет расторгнуть и вернуть его результат до конца.

Он также может быть использован внутри закрытия, чтобы избежать функцию, которая выполняет его и вернуть (и выход) в области, в которой он был определен.

В любом случае, рассматривать возвращение как нечто исключительное, и оставить его для исключительных ситуаций.

2
ответ дан 1 июня 2011 в 07:06 Источник Поделиться

Я новичок в Scala, но я хотел бы думать, что петли все-но устарело. Каждый раз, когда я вижу теперь, я думаю, "цикл - как необычно!"

Все коллекции имеют методы, которые вы можете пройти функцию. Такой подход позволяет коллекции делать различные оптимизации, особенно для многопоточных вычислений, которые сложно и трудоемко правильно программировать по своему усмотрению. Так что я бы попробовать, чтобы избавиться от цикла for и while первая.

Если вы можете как-то совместить все обрабатывать в одной функции перед передачей его в коллекцию, тем лучше.

Другие люди упомянули много других деталей, что делает ваш код более функциональным, я просто думаю, что петли наиболее очевидный стилистический элемент, который также влияет на производительность.

1
ответ дан 17 октября 2012 в 10:10 Источник Поделиться