从XQuery中删除序列中的连续数字

时间:2016-04-28 17:00:10

标签: functional-programming xquery esb osb

的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函数语言。

3 个答案:

答案 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