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

BaseX中的XQuery:从映射输出返回平均值,xquery,basex,Xquery,Basex,我试图在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="543

我试图在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>

161
82
323
319
327
并以编号作为属性(NR)和与特定搜索点的距离作为值来表示一些地理点。有些点出现不止一次(如上面示例中的点54321)。这是与内容相关的ok,因为这些是具有相同编号的点的“分支”

如果我查找这些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
 ()
让$c:=
161
82
323
319
327
对于$c中的$r//point
设$m:=map{data($r/@NR):=$r/text()}
返回
如果(map:contains($m,'54321'))那么
平均值(地图:get($m,'54321'))
其他的
()
。。。返回
323319327
,因此忽略“avg”,尽管BaseX中没有语法错误消息


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

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

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()
的简单实现可能仍然比映射更快

也就是说,要使用地图,您需要使用和构建单个新地图


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

如果您只对一个键执行此操作,则只需说
返回平均值($c/point[@NR='54321'])比使用地图更快更清晰。
。否则,您需要在键查找之间保存映射(即,在循环外部)以获得构建映射的优势。事实上,更新多个xml文件(根据映射结果插入标记)需要这样做。我的查询只是一个很小的例子:-)如何将地图保存在循环之外?谢谢大家!
让$m:=([生成映射的表达式])在$k的键列表中返回$m($k)
。但请确保目标文档上的索引是最新的,并首先尝试一个简单的非映射实现。这可能比你想象的要快。再次感谢!我一定会试试这个。也许我必须问另一个问题:-)它现在运行得很好(如果我没有遗漏什么:-)如下:
让$c:=doc('path_to_file')让$reducer:=[你的代码在这里]让$m:=[你的代码在这里]在db中为$w:open('db_name')让$p=$w/Data/point/text()返回if($p和map:contains($m,$p)),然后插入代码
{avg($m($p))}
转换为$w/Data else()
谢谢!
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'))
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'))