我正在处理命题逻辑,我编写了两个算法来收集公式中的所有变量。我希望输出是不可变的。在速度/优雅方面哪一个应该首选?还有更好的方法吗?提前谢谢。
def getVariables(formula: Formula): Set[Variable] = formula match {
case v: Variable => HashSet(v)
case Negation(f) => getVariables(f)
case BinaryConnective(f0, f1) => getVariables(f0) ++ getVariables(f1)
case _ => HashSet.empty[Variable]
}
def getVariables2(formula: Formula): Set[Variable] = {
def getVariables2(formula: Formula, set: mutable.HashSet[Variable]): Unit = formula match {
case v: Variable => set += v
case Negation(f) => getVariables2(f, set)
case BinaryConnective(f0, f1) => getVariables2(f0, set); getVariables2(f1, set)
case _ =>
}
val set = mutable.HashSet.empty[Variable]
getVariables2(formula, set)
set.toSet
}
答案 0 :(得分:1)
最快的方法几乎总是使用建设者。所以,假设没有堆栈溢出:
def getVars(formula: Formula): Set[Variable] = {
val sb = Set.newBuilder[Variable]
def inner(formula: Formula) { formula match {
case v: Variable => sb += v
case Negation(f) => inner(f)
case BinaryConnective(f0, f1) => inner(f0); inner(f1)
case _ =>
}}
inner(formula)
sb.result
}
然而,你的第一个版本可能是最优雅的。
请注意,如果您可能有非常大的公式,则此递归解决方案可能存在堆栈溢出的危险。修复相对简单:
def getVars2(formula: Formula): Set[Variable] = {
val sb = Set.newBuilder[Variable]
def inner(formulas: List[Formula]) {
var more: List[Formula] = Nil
formulas.foreach{ _ match {
case v: Variable => sb += v
case Negation(f) => more = f :: more
case BinaryConnective(f0, f1) => more = f1 :: f0 :: more
case _ =>
}}
if (!more.isEmpty) inner(more)
}
inner(formula :: Nil)
sb.result
}
你的名字太长了,无法方便地输入一个有趣的非微小表达式,但如果我们缩写为大写字母,那么:
BC(N(V('x)), BC(BC(V('a),V('x)),V('y)))
使用getVars
比第一个解决方案快约7倍; getVars2
稍慢(仅快4倍)。
(基准时间是:
getVariables 1380 ns +- 20 ns
getVars 190 ns +- 10 ns
getVars2 360 ns +- 10 ns
)