如何在Scala中对Python或运算符进行近似设置比较?
发布时间:2020-12-16 19:08:16 所属栏目:安全 来源:网络整理
导读:在听到最新的Stack Overflow播客后,Peter Norvig的紧凑型 Python拼写检查器引起了我的兴趣,所以我决定在Scala中实现它,如果我能用功能Scala成语表达它,还要看看需要多少行代码. 这是整个问题. (我们还不比较代码行.) (两个注意事项:如果您愿意,可以在Scala
在听到最新的Stack Overflow播客后,Peter Norvig的紧凑型
Python拼写检查器引起了我的兴趣,所以我决定在Scala中实现它,如果我能用功能Scala成语表达它,还要看看需要多少行代码.
这是整个问题. (我们还不比较代码行.) (两个注意事项:如果您愿意,可以在Scala解释器中运行它.如果您需要big.txt或整个项目的副本,则为on GitHub.) import scala.io.Source val alphabet = "abcdefghijklmnopqrstuvwxyz" def train(text:String) = { "[a-z]+".r.findAllIn(text).foldLeft(Map[String,Int]() withDefaultValue 1) {(a,b) => a(b) = a(b) + 1} } val NWORDS = train(Source.fromFile("big.txt").getLines.mkString.toLowerCase) def known(words:Set[String]) = {Set.empty ++ (for(w <- words if NWORDS contains w) yield w)} def edits1(word:String) = { Set.empty ++ (for (i <- 0 until word.length) // Deletes yield (word take i) + (word drop (i + 1))) ++ (for (i <- 0 until word.length - 1) // Transposes yield (word take i) + word(i + 1) + word(i) + (word drop (i + 2))) ++ (for (i <- 0 until word.length; j <- alphabet) // Replaces yield (word take i) + j + (word drop (i+1))) ++ (for (i <- 0 until word.length; j <- alphabet) // Inserts yield (word take i) + j + (word drop i)) } def known_edits2(word:String) = {Set.empty ++ (for (e1 <- edits1(word); e2 <- edits1(e1) if NWORDS contains e2) yield e2)} def correct(word:String) = { val options = Seq(() => known(Set(word)),() => known(edits1(word)),() => known_edits2(word),() => Set(word)) val candidates = options.foldLeft(Set[String]()) {(a,b) => if (a.isEmpty) b() else a} candidates.foldLeft("") {(a,b) => if (NWORDS(a) > NWORDS(b)) a else b} } 具体来说,我想知道我能用正确的功能做些什么更清洁.在原始Python中,实现更清晰: def correct(word): candidates = known([word]) or known(edits1(word)) or known_edits2(word) or [word] return max(candidates,key=NWORDS.get) 显然在Python中,空集将评估为布尔值False,因此只会评估返回非空集的第一个候选项,从而节省对edits1和known_edits2的潜在昂贵调用. 我想出的唯一解决方案是你在这里看到的版本,其中匿名函数的Seq被调用,直到一个返回一个非空的Set,最后一个保证做. 经验丰富的Scala主管,是否有更复杂的语法或更好的方法呢?提前致谢! 解决方法
迭代器也很懒(虽然不是很有用,因为你只能迭代它们一次.)所以,你可以这样做:
def correct(word: String) = { val sets = List[String => Set[String]]( x => known(Set(x)),x => known(edits1(x)),known_edits2 ).elements.map(_(word)) sets find { !_.isEmpty } match { case Some(candidates: Set[String]) => candidates.reduceLeft { (res,n) => if (NWORDS(res) > NWORDS(n)) res else n } case None => word } } 作为奖励,Iterator的find()方法不会强制评估下一个元素. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |