Search code examples
xquerymarklogicmarklogic-8

Sorting multiple maps in marklogic 8


This is more of an XQuery than MarkLogic. I have three map:map and each map has key-value pair of "id" and score. I would like to sort all the distinct ids based on the score from each maps. For eg:

map1 : 1:2048, 5:2000
map2 : 2:5000, 1:1000, 4:3000
map3 : 6:100, 7:5000, 2:2000

In the above example, each map is id:score for key value (did not know how to represent here :))..

I want the sorted list of id from three maps based on score..

Is there a good way or better way of doing the sorting, or do I have to union the keys of the map and iterate the sequence of keys and sort them ?


Solution

  • This seems like a great use case for folding. Its part of Xquery 3.0 spec.

    Folding can go through a sequence of items and gets the result for each item as it goes through. In this example $combinedMaps is the result of the last call and $mapToMerge is the item in the sequence it is currently going through.

    Here an example of what you would want to do.

       declare function local:sortMaps(
      $newMap as map:map,
      $mapA as map:map,
      $mapB as map:map
    ) as map:map {
      let $build :=
        for $key in map:keys($mapA)
        let $otherMapValue :=
          (map:get($mapB, $key), 0)[1]
        let $value := map:get($mapA, $key)
        return 
          if ($value gt $otherMapValue) then (
            map:put($newMap, $key, $value)
          ) else (
            map:put($newMap, $key, $otherMapValue)
          )
      return $newMap
    };
    
    let $map1 := 
      map:new((
        map:entry("1",2048),
        map:entry("5",2000)
      ))
    
    let $map2 := 
      map:new((
        map:entry("2",5000),
        map:entry("1",1000),
        map:entry("4",3000)
      ))
    
    let $map3 := 
      map:new((
        map:entry("6",100),
        map:entry("7",5000),
        map:entry("2",2000)
      ))
    
    let $maps := ($map1, $map2, $map3)
    return
      fn:fold-left(
        function($combinedMaps, $mapToMerge) {
          let $newMap := map:map()
          let $newMap := local:sortMaps($newMap, $combinedMaps, $mapToMerge)
          let $newMap := local:sortMaps($newMap, $mapToMerge, $combinedMaps)
          return $newMap
        }, 
        $maps[1], 
        $maps
      )