Home > front end >  For loop in dictionary in XQuery
For loop in dictionary in XQuery

Time:04-05

I am trying to loop over items and output number of occurrences for each one, but it outputs the same dictionary a number of times equal to the number of items. Is there a way same as using parentheses to just make the loops for let statements. I know that XQuery is a functional language and that I can use group by but it is not supported in marklogic.

xquery version "1.0-ml";
let $dict := map:map()
for $i in ('book1','book2','book2')
let $n := (if (map:contains($dict, $i)) then (map:get($dict, $i)) else (0))
let $dict1 := map:put($dict, $i, 1   $n)
return $dict

Output:

<map:map>
<map:entry key="book1">
<map:value xsi:type="xs:integer">1</map:value>
</map:entry>
<map:entry key="book2">
<map:value xsi:type="xs:integer">2</map:value>
</map:entry>
</map:map>
map as 
XML
<map:map>
<map:entry key="book1">
<map:value xsi:type="xs:integer">1</map:value>
</map:entry>
<map:entry key="book2">
<map:value xsi:type="xs:integer">2</map:value>
</map:entry>
</map:map>
map as 
XML
<map:map>
<map:entry key="book1">
<map:value xsi:type="xs:integer">1</map:value>
</map:entry>
<map:entry key="book2">
<map:value xsi:type="xs:integer">2</map:value>
</map:entry>
</map:map>

CodePudding user response:

In addition to the answer of @MadsHansen you could also use more functions:

xquery version "1.0-ml";

let $dict := map:map()
let $myvalues := ('book1','book2','book2')
let $_ :=
  for $i in fn:distinct-values($myvalues)
    return map:put($dict, $i, count(index-of($i, $myvalues)))
return $dict

(I picked the "frequency" function with the combination of count and index-of from another answer on stack overflow)

CodePudding user response:

You can let a throwaway variable and then put the for loop FLWOR processing for that variable, then return the $dict map:

xquery version "1.0-ml";
let $dict := map:map()
let $_ :=
  for $i in ('book1','book2','book2')
  let $n := if (map:contains($dict, $i)) then map:get($dict, $i) else 0
  return map:put($dict, $i, 1   $n)
return $dict

Since map:put() returns an empty sequence, you could also return a sequence with the for-loop processing and then the $dict:

xquery version "1.0-ml";
let $dict := map:map()
return (
  for $i in ('book1','book2','book2')
  let $n := if (map:contains($dict, $i)) then map:get($dict, $i) else 0
  return map:put($dict, $i, 1   $n), 
  $dict
)

A more concise version of the same processing:

xquery version "1.0-ml";
let $dict := map:map()
let $_ := ('book1','book2','book2') ! map:put($dict, ., 1   head((map:get($dict, .), 0)))
return $dict
  • Related