2013-01-04 4 views
0

지도의 출력을 관리하려고합니다. BaseX에서 get 함수를 사용하고 있습니다.BaseX의 XQuery : 매핑의 출력에서 ​​평균값을 반환합니다.

<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을 조회하면 평균 거리입니다.

내 쿼리 : BaseX에는 구문 오류 메시지가 없지만

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을 반환은 따라서 "평균"무시합니다.

어떻게하면됩니까? 미리 많은 감사드립니다!

답변

2

지도는 하나의 키를 하나의 값과 연결합니다. 여기서 실제로하는 것은 for 루프의 모든 반복에 대해 단일 항목 맵 $m을 작성하는 것입니다. 코드는 다음과 정확히 동일하다 :

당신은 단지 하나의 키를 찾고 있다면
for $r in $c/point 
return if ($r/@NR eq '54321') then avg($r/text()) else() 

, 난 당신이 전혀지도를 사용하고 단지 인이 작업을 수행하지 않는 것이 좋습니다 훨씬 간단하고 빠른 :

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

복수 키를 찾고 있어도 group by 또는 distinct-values()을 사용하는 순진한 구현은 쿼리하는 문서에 BaseX에 새로운 특성 색인이있는 경우 맵보다 빠를 수 있습니다.

대신 그룹에 의해 당신은 당신이 사용하는 기능 감소합니다 ( fold- 기능) 할 수 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')) 

를 사용하여 하나의 새로운지도를 구축 할 필요가지도를 사용하려면 말했다 :

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')) 

생산 코드에 당신이 속도 benefi을 보는 희망을 가지고지도를 번 를 생성 한 다음 키 조회 목록을 사용할 필요가 기억 지도를 사용하지 마십시오.

+0

대단히 감사합니다! –

+0

하나의 키에 대해서만이 작업을 수행하는 경우 맵을 사용하는 대신'return avg ($ c/point [@ NR = '54321'])'을 사용하는 것이 더 빠르고 명확합니다. 그렇지 않으면지도를 만드는 이점을 얻기 위해 주요 조회 (즉, 루프 외부) 사이에지도를 저장해야합니다. –

+0

실제로 이것은 여러 xml 파일을 업데이트 (매핑 결과에 따라 태그 삽입)해야합니다. 내 쿼리는 단지 최소한의 예였습니다 :-) 루프 외부에 어떻게 맵을 저장할 수 있습니까? 고맙습니다! –