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のように)。これらは同じ番号のポイントの「ブランチ」であるため、これはコンテンツ関連の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
 ()

...はを返します323 319 327 。したがって、BaseXには構文エラーメッセージはありませんが、「avg」は無視されます。

どうすれば上記を達成できますか?よろしくお願いします!

4

1 に答える 1

2

マップは、1つのキーを1つの値に関連付けます。ここで実際に行っているのは、ループ$mの反復ごとに1つの単一エントリマップを作成することです。forあなたのコードはこれとまったく同じです:

for $r in $c/point
return if ($r/@NR eq '54321') then avg($r/text()) else ()

キーを1つだけ検索する場合は、マップをまったく使用せずに、これを実行することをお勧めします。これは、はるかに簡単で高速です。

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-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 に答える