我是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
}
答案 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")