0

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

映射文件如下所示:

 <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 中没有语法错误消息。

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

4

1 回答 1

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 by或者distinct-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-函数)而不是 group-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 $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'))

请记住,在生产代码中,您需要生成一次映射,然后使用您的键查找列表来查看使用映射带来的速度优势。

于 2013-01-04T16:41:23.283 回答