BaseX中的XQuery:从映射输出返回平均值
我试图在BaseX中管理map:get函数的输出 映射文件如下所示: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
<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'))