我是使用Xpath2的XSLT3的Saxon 9.5EE实现,并寻找最快的方法来识别排序序列中的最大元素$ seq小于某个给定值$ value。
据我所知,序列中没有任何东西等同于“preceding :: sibling”。这意味着遍历序列时Xpath不如遍历XML树时敏捷。
也就是说,你不能说$ seq [。 gt $ value] [1] / preceding-sibling:item [1]因为“/”仅为节点定义,“previous-sibling”不会引用序列,而是引用相关节点的XML树。< / p>
总之...
我找到了两种方法,但它们似乎不必要地复杂。
一种方法是:
$seq[($seq!(if(. gt $value) then position() else ()))[1] - 1]
另一种方法是
<xsl:iterate select="$seq">
<xsl:variable name="pos" select="position()"/>
<xsl:if test=". gt $trial">
<xsl:text>
</xsl:text>
<xsl:sequence select="$seq[$pos - 1]"/>
<xsl:break/>
</xsl:if>
</xsl:iterate>
有更好的方法吗?
顺便说一句,测试这两个选项给出了有趣的结果。如果我只是在寻找相关项目的位置,那么它们的性能几乎完全相同。
但是,如果我实际上对值本身感兴趣,那么该选项会破坏另一个...大概是因为迭代命令导致序列已经在内存中启动了。
答案 0 :(得分:1)
怎么样:
$seq[. lt $value][last()]
答案 1 :(得分:0)
我认为递归函数是最优雅的解决方案:
function f ($seq, $value, $bestSoFar) {
if (head($seq) > $value)
then $bestSoFar
else f(tail($seq), $value, head($seq))
}
答案 2 :(得分:0)
如果您的实现将序列存储为数组,最快的方法是使用O(log n)
的二进制搜索,而不是O(n)
,就像其他答案的线性搜索一样。
如果您的实现可以通过保持范围引用来计算O(1)中的子序列,则可以使用:
function f ($seq, $value, $best) {
if (count($seq) = 0) then $best
else let $midi := (count($seq) + 1) idiv 2
return if ($seq[$midi] <= $value) then f(subsequence($seq, $midi + 1), $value, $seq[$midi])
else f(subsequence($seq, 1, $midi - 1), $value, $best)
}
否则,您可以将子序列保留为函数参数:
function f ($seq, $first, $last, $value, $best) {
if ($last < $first) then $best
else let $midi := $first + ($last - $first) idiv 2
return if ($seq[$midi] <= $value) then f($seq, $midi + 1, $last, $value, $seq[$midi])
else f($seq, $first, $midi - 1, $value, $best)
}
function call-f($seq, $value) {
f($seq, 1, count($seq), $value, ())
}