BaseX中的XQuery:从映射的输出返回avg值

时间:2013-01-04 16:06:00

标签: xquery basex

我正在尝试管理map的输出:在BaseX中获取函数。

映射文件如下所示:

 <around>
   <point NR="51151">161</point>
   <point NR="31252">82</point>
   <point NR="54321">323</point>
   <point NR="54321">319</point>
   <point NR="54321">327</point>
 </around>

表示一些地理点,其中编号为属性(NR),并且距离某个搜索点的距离为值。有一些点出现不止一次(如上例中的点54321)。这与内容相关,因为这些是具有相同编号的点的“分支”。

如果我查找这些NR,我需要得到的是距离的平均值。

我的查询:

 let $c :=
      <around>
        <point NR="51151">161</point>
        <point NR="31252">82</point>
        <point NR="54321">323</point>
        <point NR="54321">319</point>
        <point NR="54321">327</point>
      </around>
 for $r in $c//point
 let $m := map { data($r/@NR) := $r/text() }
 return
 if ( map:contains($m, '54321'  ) ) then
 avg(map:get($m, '54321'))
 else
 ()

...返回323 319 327,因此忽略了“avg”,尽管BaseX中没有语法错误消息。

我怎样才能实现上述目标?非常感谢提前!

1 个答案:

答案 0 :(得分:2)

地图将一个键与一个值相关联。你在这里实际做的是为$m循环的每次迭代创建一个单入口映射for。您的代码与此完全相同:

for $r in $c/point
return if ($r/@NR eq '54321') then avg($r/text()) else ()

如果您只查找一个键,我建议您根本不使用地图,只需执行此操作,这样更简单,更快捷:

return avg($c/point[@NR='54321'])

即使您正在查找多个密钥,如果BaseX在您查询的文档上有新的属性索引,那么使用group bydistinct-values()的简单实现可能仍然比地图更快。

也就是说,要使用地图,您需要使用map:newgroup by构建单个新地图

let $c :=
      <around>
        <point NR="51151">161</point>
        <point NR="31252">82</point>
        <point NR="54321">323</point>
        <point NR="54321">319</point>
        <point NR="54321">327</point>
      </around>
let $m := map:new(
    for $r in $c/point
    let $key := $r/@NR, $value := $r/text()
    group by $key
    return map {$key := $value}
) 
return avg($m('54321'))

您也可以使用功能缩减(fold-功能)而不是分组来执行此操作:

let $c :=
      <around>
        <point NR="51151">161</point>
        <point NR="31252">82</point>
        <point NR="54321">323</point>
        <point NR="54321">319</point>
        <point NR="54321">327</point>
      </around>
let $reducer := function($points as map(*), $point as item()) {
    map:new((
      $points, 
      map { $point/@NR := ($points($point/@NR), $point/text())}
    ))
}
let $m := fold-left($reducer, map{}, $c/point)
return avg($m('54321'))

请记住,在生产代码中,您需要生成地图一次,然后在其上使用您的密钥查找列表,以便从使用地图中获得速度优势。