I'm trying to ingest a sequence of 6293 strings, each 8 characters long, and create a map in which each key is an integer from 1 to 63, and each value is a subsequence of the 6293 strings, from ($key+1) * 100) to that starting value + 99.

I wrote a function to do this recursively (so I thought), but it runs and runs (I've given it over 5 minutes), and so I can see I borked something. I wrote a function to output the starting and ending sequence indices for each execution of the function, but it (as the only change to the first function) quickly causes a stack overflow:

Error:
Stack Overflow: Try tail recursion?

Since the recursive call was the last expression in the function, I thought I was doing tail recursion.

I'm running 11.6.0. The code with explanatory comments follows. I'd be grateful for any corrections and insights.

declare function local:write_results($elems as element()*,
                                     $count as xs:integer) {
  let $dir_path := '/home/cfbearden/projects/mesh_for_pure/20241220/data/'
  let $count_as_str := xs:string($count)
  let $content_out := <PubmedArticleSet>{$elems}</PubmedArticleSet>
  let $path := $dir_path || 'pmed2022_' || $count_as_str || '.xml'
  let $params := {
    'method' : 'xml',
    'indent' : 'yes'
  }
  return file:write($path, $elems, $params)
};

declare function local:by_hundreds($pmids as xs:string*,
                                   $pmid_map as map(*)) as map(*) {
  let $key_count := count(map:keys($pmid_map))
  return
    (: base case: each value except the last should have 100 items
       in it; the last should have <= 100; in this case we return
       the map
       goal is to build a map with 63 keys, with each value
       a sequence of 100 or 93 (in the last case) strings :)
    if ((($key_count + 1) * 100) >= count($pmids))
      then $pmid_map
    else
      (: starting index for subsequence() :)
      let $start := 1 + ($key_count * 100)
      (: ending index for subsequence() :)
      let $end := $start + 99
      (: value of the map key for this 100 items :)
      let $key := $key_count + 1
      (: attempt to log all recurrent executions to files
      let $foo := local:write_results(<res><start>{$start}</start><end>{$end}</end></res>, $key_count)
      :)
      (: create a map with $key as key and the subsequence from n to n + 99
         of $pmids and merge it with input accumulator map to make a new map :)
      let $pmid_map_new := map:merge($pmid_map, map {
        $key : subsequence($pmids, $start, $end)
      })
      (: recur; the number of keys in $pmid_map_new will enable the next
         execution to determine which items from $pmids to use :)
      return local:by_hundreds($pmids, $pmid_map_new)
};

(:
   The data format is simple:
   <DATA_RECORDS>
     <DATA_RECORD>
       <pub_uuid>0008980a-f1f3-40bf-8c13-cb0b79dfa81e</pub_uuid>
       <pmid>35732127</pmid>
     </DATA_RECORD>
     ...
   </DATA_RECORDS>
:)
let $pure_2022_db := collection('pure_2022')

(: yields a sequence of 6293 strings, all 8 characters long :)
let $pmids := (
  for $drec in $pure_2022_db/DATA_RECORDS/DATA_RECORD
    let $pmid := $drec/pmid/text()
    return $pmid
)

let $result := local:by_hundreds($pmids, {})
return $result



All the best,
Chuck Bearden