如何缩短此scala代码?

时间:2013-05-17 20:04:08

标签: algorithm scala optimization

我是Scala新手。我尝试了土耳其公民号验证算法。

如何实施和优化此scala代码?

您可以在此链接https://gist.github.com/hasanozgan/5601623

找到我的java版本
trait TurkishCitizenshipNumberValidator {

  private def odd(tckn: String): Int = {
    tckn.zipWithIndex.foldLeft(0) {
      (total, x) =>
        x match {
          case i if ((i._2 % 2 == 0 && i._2 < 10)) => ((i._1.asDigit) + total)
          case _ => total
        }
    }
  }

  private def even(tckn: String): Int = {
    tckn.zipWithIndex.foldLeft(0) {
      (total, x) =>
        x match {
          case i if ((i._2 % 2 == 1) && i._2 < 9) => ((i._1.asDigit) + total)
          case _ => total
        }
    }
  }

  private def total(tckn: String): Int = {
    tckn.zipWithIndex.foldLeft(0) {
      (total, x) =>
        x match {
          case i if (i._2 < 10) => ((i._1.asDigit) + total)
          case _ => total
        }
    }
  }

  def turkishCitizenshipNumberValidator(t: String): Boolean = {
    val digit10 = total(t) % 10
    val digit9 = ((odd(t) * 7) - even(t)) % 10

    ((t(9).asDigit == digit9) && t(10).asDigit == digit10)
  }
}

object test extends TurkishCitizenshipNumberValidator {
  // http://tckimliknouretici.appspot.com/
    turkishCitizenshipNumberValidator("29419391592")
                                                  //> res0: Boolean = true
}

4 个答案:

答案 0 :(得分:1)

嗯,你有三次相同的身体,有轻微的差异。因此,您应该将该body作为一个辅助方法,并使用附加函数参数来测试索引:

private def check(tckn: String)(pred: Int => Boolean): Int = {
  tckn.zipWithIndex.foldLeft(0) {
    (total, x) =>
      x match {
        case i if pred(i._2) => ((i._1.asDigit) + total)
        case _ => total
      }
  }
}

private def odd(tckn: String): Int = check(tckn)(i => i % 2 == 0 && i < 10)


其次,您可以通过提取字符和索引的元组来简化check代码,如果只有一个保护,则不需要模式匹配,只需简单{{1}我会做(更多的是品味问题)。

if

答案 1 :(得分:1)

这个怎么样?

def turkishCitizenshipNumberValidator(t: String): Boolean = {
  val digits = t.init.map(_.asDigit)
  val digit10 = digits.sum % 10
  val (odd, even) = digits.zipWithIndex.partition(_._2 % 2 == 0)
  val digit9 = ((odd.map(_._1).sum * 7) - even.init.map(_._1).sum) % 10

  ((t(9).asDigit == digit9) && t(10).asDigit == digit10)
}

答案 2 :(得分:1)

如果你想要它既紧凑又清晰,并且需要基本的输入验证(正确的长度,事情都是数字),我会

def turkishCitizenshipNumberValidator(t: String): Boolean = {
  if (t.length != 11 || !t.forall(_.isDigit)) false
  else {
    val n = t.map(_.asDigit)
    val evens = n.grouped(2).take(5).map(_(0)).sum
    val odds = n.grouped(2).take(4).map(_(1)).sum
    n(10) == (n.take(10).sum % 10) && n(9) == ((odds*7 - evens) % 10)
  }
}

这里的关键是使用grouped将字符串拉成偶数对,并在开始时将数字映射到数字,这样就不会太麻烦了。


编辑:如果你想混淆你的代码,试试这个!

def tCNV(t: String) = t.map(_.asDigit).foldLeft(Seq(0,0,0)){ (v,n) => v(2) match {
  case 10 => Seq(v(0)-n,v(1),0); case 9 => Seq(v(0)+n,v(1)-n,10)
  case i => Seq(v(0)+n, v(1)+n*(7*(i%2)+(i%2-1)), i+1)
}}.take(2).map(_%10).forall(_ == 0)

答案 3 :(得分:0)

对于这样的问题,需要对字符串进行解构然后处理,有时更容易将模式压缩到字符串,然后使用常用的集合方法进行处理。

在这种特殊情况下,模式是一个简单的奇偶模式,所以将公民号码拉成一串交替的字符,一两个,是开始的地方,就像这样......

def turkishCitizenshipNumberValidator( digits:String ) = {

  val pattern = Stream.continually("12".toStream).flatten  // An odd & evens pattern

  val d = digits.
          filter(_.isDigit).        // Filter out the non-digits 
          map(_.asDigit).           // Convert Char to Int
          zip(pattern)              // Zip to a repeating string of one-two's, for odd & evens

  val odds = d.take(9).filter( _._2 == '1' ).map( _._1 ).sum 
  val evens = d.take(8).filter( _._2 == '2' ).map( _._1 ).sum
  val total = d.take(10).map( _._1 ).sum 

  d.size == 11 && (odds * 7 - evens) % 10 == d(9)._1 && total % 10 == d(10)._1
}

turkishCitizenshipNumberValidator("29419391592")