我正在尝试管理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中没有语法错误消息。
我怎样才能实现上述目标?非常感谢提前!
答案 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 by
或distinct-values()
的简单实现可能仍然比地图更快。
也就是说,要使用地图,您需要使用map:new
和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 $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'))
请记住,在生产代码中,您需要生成地图一次,然后在其上使用您的密钥查找列表,以便从使用地图中获得速度优势。