我正在尝试用一串数字写一个IP生成器。生成器将输入一串数字,例如“17234
”,并将返回所有可能的ips列表,如下所示:
1.7.2.34
1.7.23.4
1.72.3.4
17.2.3.4
我尝试编写一个片段来进行生成,如下所示:
def genip(ip:String):Unit = {
def legal(ip:String):Boolean = (ip.size == 1) || (ip.size == 2) || (ip.size == 3)
def genips(ip:String,portion:Int,accum:String):Unit = portion match {
case 1 if legal(ip) => println(accum+ip)
case _ if portion > 1 => {
genips(ip.drop(1),portion-1,if(accum.size == 0) ip.take(1)+"." else accum+ip.take(1)+".")
genips(ip.drop(2),portion-1,if(accum.size == 0) ip.take(2)+"." else accum+ip.take(2)+".")
genips(ip.drop(3),portion-1,if(accum.size == 0) ip.take(3)+"." else accum+ip.take(3)+".")
}
case _ => return
}
genips(ip,4,"")
}
我们的想法是将字符串分成四个八位字节,然后将八位字节进一步分区为大小为"1","2" and "3"
的字符串,然后以递归方式下降到剩余的字符串中。
我不确定自己是否走在正确的轨道上,但如果有人能够提出一种更实用的方法,那就更好了。
由于
答案 0 :(得分:2)
以下是附加代码的替代版本:
def generateIPs(digits : String) : Seq[String] = generateIPs(digits, 4)
private def generateIPs(digits : String, partsLeft : Int) : Seq[String] = {
if ( digits.size < partsLeft || digits.size > partsLeft * 3) {
Nil
} else if(partsLeft == 1) {
Seq(digits)
} else {
(1 to 3).map(n => generateIPs(digits.drop(n), partsLeft - 1)
.map(digits.take(n) + "." + _)
).flatten
}
}
println("Results:\n" + generateIPs("17234").mkString("\n"))
主要变化:
方法现在返回字符串集合(而不是单位),因此它们是正确的函数(而不是副作用)并且可以轻松测试;
根据我们拍摄的一组数字的大小,避免重复相同的代码3次;
没有将累积的中间结果作为方法参数传递 - 在这种情况下它没有意义,因为你最多有4个递归调用,没有它就更容易阅读,尽管你丢失了在很多情况下,尾递归可能是合理的。
注意:最后map
语句是被for
理解所取代的好候选者,许多开发人员发现这些理解更容易阅读和推理,尽管我将其留作练习:)< / p>
答案 1 :(得分:1)
你的代码是正确的想法;我不确定它的功能是否对任何事情都有帮助,但我会展示出功能和副作用的方法来做你想做的事情。首先,我们想要一个很好的例程来确定一些数字,确保剩下的分组留下一个好的数字,并确保它们在IP的范围内:
def validSize(i: Int, len: Int, more: Int) = i + more <= len && i + 3*more >= len
def chunk(s: String, more: Int) = {
val parts = for (i <- 1 to 3 if validSize(i, s.length, more)) yield s.splitAt(i)
parts.filter(_._1.toInt < 256)
}
现在我们需要递归四次使用chunk来生成可能性。这是一个内部可迭代的迭代解决方案:
def genIPs(digits: String) = {
var parts = List(("", digits))
for (i <- 1 to 4) {
parts = parts.flatMap{ case (pre, post) =>
chunk(post, 4-i).map{ case (x,y) => (pre+x+".", y) }
}
}
parts.map(_._1.dropRight(1))
}
这是使用Iterator
进行递归的方法:
def genIPs(digits: String) = Iterator.iterate(List((3,"",digits))){ _.flatMap{
case(j, pre, post) => chunk(post, j).map{ case(x,y) => (j-1, pre+x+".", y) }
}}.dropWhile(_.head._1 >= 0).next.map(_._2.dropRight(1))
逻辑是相同的。这是工作:
scala> genIPs("1238516")
res2: List[String] = List(1.23.85.16, 1.238.5.16, 1.238.51.6,
12.3.85.16, 12.38.5.16, 12.38.51.6,
123.8.5.16, 123.8.51.6, 123.85.1.6)