map:merge
Returns a map that combines the entries from a number of existing maps.
Signatures
map:merge($maps as map(*)*) as map(*)
map:merge(
$maps as map(*)*,
$options as map(*)
) as map(*)
Properties
This function is deterministic, context-independent, and focus-independent.
Rules
The function map:merge
returns a map that
is formed by combining the contents of the maps supplied in the $maps
argument.
Informally, the supplied maps are combined as follows:
-
There is one entry in the returned map for each distinct key present in the union of the input maps, where two keys are distinct if they are not the same key.
-
If there are duplicate keys, that is, if two or more maps contain entries having the same key, then the way this is handled is controlled by the second (
$options
) argument.
The definitive specification is as follows.
-
The effect of calling the single-argument function is the same as the effect of calling the two-argument function with an empty map as the value of
$options
. -
The
$options
argument can be used to control the way in which duplicate keys are handled. The option parameter conventions apply. -
The entries that may appear in the
$options
map are as follows:Key Value Meaning duplicates
Determines the policy for handling duplicate keys: specifically, the action to be taken if two maps in the input sequence $maps
contain entries with key values K1 and K2 where K1 and K2 are the same key.-
Type:
xs:string
-
Default:
use-first
reject
An error is raised [ERRFOJS0003] if duplicate keys are encountered. use-first
If duplicate keys are present, all but the first of a set of duplicates are ignored, where the ordering is based on the order of maps in the $maps
argument.use-last
If duplicate keys are present, all but the last of a set of duplicates are ignored, where the ordering is based on the order of maps in the $maps
argument.use-any
If duplicate keys are present, all but one of a set of duplicates are ignored, and it is implementation-dependent which one is retained. combine
If duplicate keys are present, the result map includes an entry for the key whose associated value is the sequence-concatenation of all the values associated with the key, retaining order based on the order of maps in the $maps
argument. The key value in the result map that corresponds to such a set of duplicates must be the same key as each of the duplicates, but it is otherwise unconstrained: for example if the duplicate keys arexs:byte(1)
andxs:short(1)
, the key in the result could legitimately bexs:long(1)
. -
The result of the function call map:merge($MAPS, $OPTIONS)
is defined to be consistent with the result of the expression:
let $FOJS0003 := QName("http://www.w3.org/2005/xqt-errors", "FOJS0003"),
$duplicates-handler := map {
"use-first": function($a, $b) {$a},
"use-last": function($a, $b) {$b},
"combine": function($a, $b) {$a, $b},
"reject": function($a, $b) {fn:error($FOJS0003)},
"use-any": function($a, $b) {fn:random-number-generator()?permute(($a, $b))[1]}
},
$combine-maps := function($A as map(*), $B as map(*), $deduplicator as function(*)) {
fn:fold-left(map:keys($B), $A, function($z, $k){
if (map:contains($z, $k))
then map:put($z, $k, $deduplicator($z($k), $B($k)))
else map:put($z, $k, $B($k))
})
}
return fn:fold-left($MAPS, map{},
$combine-maps(?, ?, $duplicates-handler(($OPTIONS?duplicates, "use-first")[1]))
By way of explanation,
$combine-maps
is a function that combines two maps by iterating over the keys of the second map, adding each key and its corresponding value to the first map as it proceeds. The second call offn:fold-left
in thereturn
clause then iterates over the maps supplied in the call tomap:merge
, accumulating a single map that absorbs successive maps in the input sequence by calling$combine-maps
.This algorithm processes the supplied maps in a defined order, but processes the keys within each map in implementation-dependent order.
The use of
fn:random-number-generator
represents one possible conformant implementation for"duplicates":"use-any"
, but it is not the only conformant implementation and is not intended to be a realistic implementation. The purpose of this option is to allow the implementation to use whatever strategy is most efficient; for example, if the input maps are processed in parallel, then specifying"duplicates":"use-any"
means that the implementation does not need to keep track of the original order of the sequence of input maps.
Error Conditions
An error is raised [ERRFOJS0003] if the value of
$options
indicates that duplicates are to be rejected, and a duplicate key is encountered.
An error is raised [ERRFOJS0005] if the value of
$options
includes an entry whose key is defined
in this specification, and whose value is not a permitted value for that key.
Notes
If the input is an empty sequence, the result is an empty map.
If the input is a sequence of length one, the result map is indistinguishable from the supplied map.
There is no requirement that the supplied input maps should have the same or compatible
types. The type of a map (for example map(xs:integer, xs:string)
) is
descriptive of the entries it currently contains, but is not a constraint on how the
map
may be combined with other maps.
Examples
let $week := map{0:"Sonntag", 1:"Montag", 2:"Dienstag",
3:"Mittwoch", 4:"Donnerstag", 5:"Freitag", 6:"Samstag"}
The expression map:merge(())
returns map{}
. (Returns an empty map).
The expression map:merge((map:entry(0, "no"), map:entry(1, "yes")))
returns map{0:"no", 1:"yes"}
. (Returns a map with two entries).
The expression map:merge(($week, map{7:"Unbekannt"}))
returns map{0:"Sonntag", 1:"Montag", 2:"Dienstag", 3:"Mittwoch", 4:"Donnerstag",
5:"Freitag", 6:"Samstag", 7:"Unbekannt"}
. (The value of the existing map is unchanged; the returned map
contains all the entries from $week
, supplemented with an additional
entry.)
The expression map:merge(($week, map{6:"Sonnabend"}), map{"duplicates":"use-last"})
returns map{0:"Sonntag", 1:"Montag", 2:"Dienstag", 3:"Mittwoch", 4:"Donnerstag",
5:"Freitag", 6:"Sonnabend"}
. (The value of the existing map is unchanged; the returned map
contains all the entries from $week
, with one entry replaced by a
new entry. Both input maps contain an entry with the key 6
; the
one used in the result is the one that comes last in the input
sequence.)
The expression map:merge(($week, map{6:"Sonnabend"}), map{"duplicates":"use-first"})
returns map{0:"Sonntag", 1:"Montag", 2:"Dienstag", 3:"Mittwoch", 4:"Donnerstag",
5:"Freitag", 6:"Samstag"}
. (The value of the existing map is unchanged; the returned map
contains all the entries from $week
, with one entry replaced by a
new entry. Both input maps contain an entry with the key 6
; the
one used in the result is the one that comes first in the input
sequence.)
The expression map:merge(($week, map{6:"Sonnabend"}), map{"duplicates":"combine"})
returns map{0:"Sonntag", 1:"Montag", 2:"Dienstag", 3:"Mittwoch", 4:"Donnerstag",
5:"Freitag", 6:("Samstag", "Sonnabend")}
. (The value of the existing map is unchanged; the returned map
contains all the entries from $week
, with one entry replaced by a
new entry. Both input maps contain an entry with the key 6
; the
entry that appears in the result is the sequence-concatenation of the entries
in the input maps, retaining order.)