的XQuery
输入 :( 1,2,3,4,5,6,7,14,15,16,17,24,25,26,27,28)
输出 :( 1,7,14,17,24,28)
我尝试使用XQuery函数从输入序列中删除连续数字但是没有这样做
xquery version "1.0" encoding "utf-8";
declare namespace ns1="http://www.somenamespace.org/types";
declare variable $request as xs:integer* external;
declare function local:func($reqSequence as xs:integer*) as xs:integer* {
let $nonRepeatSeq := for $count in (1 to count($reqSequence)) return
if ($reqSequence[$count+1] - $reqSequence) then
remove($reqSequence,$count+1)
else ()
return
$nonRepeatSeq
};
local:func((1,2,3,4,5,6,7,14,15,16,17,24,25,26,27,28))
请建议如何使用XQuery函数语言。
答案 0 :(得分:3)
在XQuery中执行此操作的两种简单方法。两者都依赖于能够将值序列分配给变量,以便我们可以在需要时查看它的各个成员对。
首先,迭代值并选择(a)第一个值,(b)任何不大于其前任值的值,以及(c)任何不小于其后继值的值。 [OP指出还需要包含最后一个值;留给读者的练习。或者看看Michael Kay的答案,它提供了过滤器的更简洁的表述;德摩根法再次罢工!]
let $vseq := (1,2,3,4,5,6,7,14,15,16,17,24,25,26,27,28)
for $v at $pos in $vseq
return if ($pos eq 1
or $vseq[$pos - 1] ne $v - 1
or $vseq[$pos + 1] ne $v + 1)
then $v
else ()
或者,第二,在过滤器表达式中做大致相同的事情:
let $vseq := (1,2,3,4,5,6,7,14,15,16,17,24,25,26,27,28)
return $vseq[
for $i in position() return
$i eq 1
or . ne $vseq[$i - 1] + 1
or . ne $vseq[$i + 1] - 1]
这两种执行计算方式与非工作尝试之间的主要区别在于,他们没有提及有关更改或修改序列的任何内容;他们只是指定一个新序列。通过使用过滤器表达式,第二个公式明确表示结果将是$ vseq的子序列; for
表达式一般没有这样的保证(尽管因为每个值它返回空序列或值本身,我们可以看到这里结果也是一个子序列:$ vseq的副本一些值已被省略。
许多程序员发现很难在分配变量或修改数据结构方面停止思考,但值得付出一些努力。
[附录]我可能忽略了一些东西,但是我没有看到在纯XPath 2.0中表达这种计算的方法,因为XPath 2.0似乎没有任何机制可以将$vseq
之类的变量绑定到一个非单一的值序列。 (XPath 3.0有let
个表达式,因此它不是一个挑战。上面的第二个公式本身就是纯XPath 3.0。)
答案 1 :(得分:2)
在XSLT中,这可以完成:
<xsl:for-each-group select="$in" group-adjacent=". - position()">
<xsl:sequence select="current-group()[1], current-group()[last()]"/>
</xsl:for-each-group>
在XQuery 3.0中,你可以使用翻滚窗口来完成它,但是我懒得弄清楚细节。
XPath 2.0解决方案(假设输入序列在$in
中)是:
for $i in 1 to count($in)
return $in[$i][not(. eq $in[$i - 1]+1 and . eq $in[$i+1]-1)]
答案 2 :(得分:0)
您的解决方案中存在多个逻辑和XQuery使用错误,但它的主要问题是XQuery中的变量是不可变的,因此一旦分配了值,您就无法将值重新分配给它。因此,在递归解决方案中考虑这些类型的问题通常更容易:
declare function local:non-consec(
$prev as xs:integer?,
$rest as xs:integer*
) as xs:integer*
{
if (empty($rest)) then ()
else
let $curr := head($rest)
let $next := subsequence($rest, 2, 1)
return (
if ($prev eq $curr - 1 and $curr eq $next - 1)
then () (: This number is part of a consecutive sequence :)
else $curr,
local:non-consec(head($rest), tail($rest))
)
};
local:non-consec((), (1,2,3,4,5,6,7,14,15,16,17,24,25,26,27,28))
=>
1
7
14
17
24
28