我正在看Perl code golf page(不要问为什么)并且遇到了这个:
第3洞 - 最小重复模式
编写一个子程序,接受一个可能由a组成的字符串 重复模式,并返回最小的重复子字符串。如果 字符串不包含重复模式,即子例程 应该返回undef或空字符串。 e.g:
input output
'aaaaaa' 'a'
'ababab' 'ab'
'aabaab' 'aab'
'ababaa' ''
显然在Perl中,这可以表示为sub g3 { pop=~/^(.*?)\1+\z/s&&$1 }
我不太了解Perl,所以我不明白它是如何工作的。我们在Scala能做的最好的事情是什么?我对优雅感兴趣而不是精确的角色数。
这是我的尝试,但这很难看,这就是我要问的原因。
def srp(s: String) =
s.inits.toList.tail.init.map(i => (i * (s.size / i.size), i)).
filter(_._1 == s).map(_._2).reverse.headOption.getOrElse("")
答案 0 :(得分:7)
优雅是主观的......
def smallestPat(input: String) = {
(1 to input.length).view
.map(i => input.take(i))
.find{p =>
Iterator.iterate(p)(_ + p)
.takeWhile(_.length <= input.length)
.exists(_ == input) && p != input}
.getOrElse("")
}
List("aaaaaa", "ababab", "aabaab", "ababaa") map smallestPat
// res13: List[String] = List(a, ab, aab, "")
编辑并重新编辑:略微缩短:
def smallestPat(i: String) = {
(1 to i.length - 1)
.map(i.take)
.find(p => p * (i.length / p.length) == i)
.getOrElse("")
}
再使用grouped
:
def smallestPat(i: String) = {
(1 to i.size/2).map(i.take)
.find(p => i.grouped(p.size) forall(p==))
.getOrElse("")
}
答案 1 :(得分:7)
您是否愿意接受基于Regex
的解决方案?
def srp(s: String) = {
val M = """^(.*?)\1+$""".r
s match {
case M(m) => Some(m)
case _ => None
}
}
或者单行:
val srp = """^(.*?)\1+$""".r.findFirstMatchIn(_: String).map(_.group(1))
不像Perl那样简洁,但我发现两者都更具可读性。
答案 2 :(得分:2)
这是等效的Scala单行程序:
"""(?:^(.*?)\1+$)|.*""".r replaceAllIn (_: String, "$1")