Hi -- In BaseX 8.2.1, I have a bunch of maps; the maps may have some overlap of key values. I would like to merge/find the union of all of these maps while retaining all the values associated with each key in the resulting map-of-all-maps. (Combined map? Any word can be wrong, here! :) map:merge() doesn't do this; http://docs.basex.org/wiki/Map_Module#map:merge says "The associated value for each such key is taken from the last map in the input sequence $input that contains an entry with this key." and testing confirms this. Is there a straightforward way to do this that I'm missing? Thanks! Graydon
Hi Graydon, have a look here https://github.com/xokomola/fold/blob/dbb79c60a7356e32a0994e581ad4f7f5377ddc... hope it helps --Marc
On 15 jul. 2015, at 20:01, Graydon Saunders <graydonish@gmail.com> wrote:
Hi --
In BaseX 8.2.1, I have a bunch of maps; the maps may have some overlap of key values. I would like to merge/find the union of all of these maps while retaining all the values associated with each key in the resulting map-of-all-maps. (Combined map? Any word can be wrong, here! :)
map:merge() doesn't do this; http://docs.basex.org/wiki/Map_Module#map:merge says "The associated value for each such key is taken from the last map in the input sequence $input that contains an entry with this key." and testing confirms this.
Is there a straightforward way to do this that I'm missing?
Thanks! Graydon
Looking at that code again I think it should be rewritten to use map:for-each it's too convoluted, but it probably gives you an idea of how to proceed. Here's a test that shows how it works. https://github.com/xokomola/fold/blob/dbb79c60a7356e32a0994e581ad4f7f5377ddc... --Marc
On 15 jul. 2015, at 21:51, Marc van Grootel <marc.van.grootel@gmail.com> wrote:
Hi Graydon, have a look here https://github.com/xokomola/fold/blob/dbb79c60a7356e32a0994e581ad4f7f5377ddc...
hope it helps
--Marc
On 15 jul. 2015, at 20:01, Graydon Saunders <graydonish@gmail.com> wrote:
Hi --
In BaseX 8.2.1, I have a bunch of maps; the maps may have some overlap of key values. I would like to merge/find the union of all of these maps while retaining all the values associated with each key in the resulting map-of-all-maps. (Combined map? Any word can be wrong, here! :)
map:merge() doesn't do this; http://docs.basex.org/wiki/Map_Module#map:merge says "The associated value for each such key is taken from the last map in the input sequence $input that contains an entry with this key." and testing confirms this.
Is there a straightforward way to do this that I'm missing?
Thanks! Graydon
Hi Marc -- That looks very helpful. (Just as soon as I get over feeling like a cabbage for forgetting about fold-left()!) thanks! Graydon On Wed, Jul 15, 2015 at 3:51 PM, Marc van Grootel < marc.van.grootel@gmail.com> wrote:
Hi Graydon, have a look here https://github.com/xokomola/fold/blob/dbb79c60a7356e32a0994e581ad4f7f5377ddc...
hope it helps
--Marc
On 15 jul. 2015, at 20:01, Graydon Saunders <graydonish@gmail.com> wrote:
Hi --
In BaseX 8.2.1, I have a bunch of maps; the maps may have some overlap of key values. I would like to merge/find the union of all of these maps while retaining all the values associated with each key in the resulting map-of-all-maps. (Combined map? Any word can be wrong, here! :)
map:merge() doesn't do this; http://docs.basex.org/wiki/Map_Module#map:merge says "The associated value for each such key is taken from the last map in the input sequence $input that contains an entry with this key." and testing confirms this.
Is there a straightforward way to do this that I'm missing?
Thanks! Graydon
Van: Rob Stapper [mailto:r.stapper@lijbrandt.nl] Verzonden: donderdag 16 juli 2015 8:48 Aan: 'Graydon Saunders' Onderwerp: RE: [basex-talk] Union of maps? Hoi Graydon, Here’s one of my map-extensions. This one I use for merging maps. It’s also an example of how to create your own high-order-functions. Hopes is it helps. Cheers, Rob Stapper declare function ext.map:merge ( $sourceMap as map(*) , $targetMap as map(*) , $updateFunction as function(*) ) as map(*) { fold-left( map:keys( $sourceMap) , $targetMap , function( $targetMap , $key ) { map:put( $targetMap , $key , $updateFunction( map:get( $sourceMap, $key) , map:get( $targetMap, $key) ) ) } ) } ; Van: basex-talk-bounces@mailman.uni-konstanz.de [mailto:basex-talk-bounces@mailman.uni-konstanz.de] Namens Graydon Saunders Verzonden: woensdag 15 juli 2015 20:01 Aan: BaseX Onderwerp: [basex-talk] Union of maps? Hi -- In BaseX 8.2.1, I have a bunch of maps; the maps may have some overlap of key values. I would like to merge/find the union of all of these maps while retaining all the values associated with each key in the resulting map-of-all-maps. (Combined map? Any word can be wrong, here! :) map:merge() doesn't do this; http://docs.basex.org/wiki/Map_Module#map:merge says "The associated value for each such key is taken from the last map in the input sequence $input that contains an entry with this key." and testing confirms this. Is there a straightforward way to do this that I'm missing? Thanks! Graydon --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus
Van: Rob Stapper [mailto:r.stapper@lijbrandt.nl] Verzonden: donderdag 16 juli 2015 9:08 Aan: 'Graydon Saunders' Onderwerp: RE: [basex-talk] Union of maps? Just as Marc: after looking at the code I found it needed tweeking ;-) Here’s a tweeked version. Succes, Rob declare function XQR.map:merge ( $sourceMap as map(*) , $targetMap as map(*) , $updateFunction as function(*) ) as map(*) { fold-left( map:keys( $sourceMap) , $targetMap , function( $targetMap , $key ) { let $go := function( $sourceEntry ) { item:exists( map:get( $targetMap , $key ) , function( $targetEntry ) { map:put( $targetMap , $key , $updateFunction( $sourceEntry , $targetEntry ) ) } , map:put( $targetMap , $key , $sourceEntry ) ) } return $go( map:get( $sourceMap , $key ) ) } ) } ; Plus bonus: declare %basex:inline function item:exists ( $item , $existProcessor , $emptyValue ) { if ( exists( $item)) then $existProcessor( $item) else $emptyValue } ; Van: basex-talk-bounces@mailman.uni-konstanz.de [mailto:basex-talk-bounces@mailman.uni-konstanz.de] Namens Graydon Saunders Verzonden: woensdag 15 juli 2015 20:01 Aan: BaseX Onderwerp: [basex-talk] Union of maps? Hi -- In BaseX 8.2.1, I have a bunch of maps; the maps may have some overlap of key values. I would like to merge/find the union of all of these maps while retaining all the values associated with each key in the resulting map-of-all-maps. (Combined map? Any word can be wrong, here! :) map:merge() doesn't do this; http://docs.basex.org/wiki/Map_Module#map:merge says "The associated value for each such key is taken from the last map in the input sequence $input that contains an entry with this key." and testing confirms this. Is there a straightforward way to do this that I'm missing? Thanks! Graydon --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus
Or, retweeked and made for multiple maps (@ Marc thanx for the inspiration) declare function XQR.map:merge ( $mapSet as map(*)* , $mergeFunction as function(*) ) as map(*) { fold-left( $mapSet , map {} , function( $targetMap , $sourceMap ) { map:merge(( $targetMap , $sourceMap , for-each( map:keys( $targetMap)[ . = map:keys( $sourceMap)] , function( $key ) { map:entry( $key , $mergeFunction( map:get( $targetMap, $key) , map:get( $sourceMap, $key) ) ) } ) )) } ) } ; Use: xqr.map:merge( ( map { 'a' : ( 1,2,3,4) , 'b' : ( 4,5,6,7) } , map { 'b' : ( 6,7,8,9) , '7' : ( 'x', 'y', 'z') } , map { 'b' : ( 9,10,12) , '7' : ( 'x', 'y', 'p') } ) , function( $data1 , $data2 ) { distinct-values(( $data1, $data2)) } ) ! map:serialize( .) You’re welcome, Rob Van: basex-talk-bounces@mailman.uni-konstanz.de [mailto:basex-talk-bounces@mailman.uni-konstanz.de] Namens Graydon Saunders Verzonden: woensdag 15 juli 2015 20:01 Aan: BaseX Onderwerp: [basex-talk] Union of maps? Hi -- In BaseX 8.2.1, I have a bunch of maps; the maps may have some overlap of key values. I would like to merge/find the union of all of these maps while retaining all the values associated with each key in the resulting map-of-all-maps. (Combined map? Any word can be wrong, here! :) map:merge() doesn't do this; http://docs.basex.org/wiki/Map_Module#map:merge says "The associated value for each such key is taken from the last map in the input sequence $input that contains an entry with this key." and testing confirms this. Is there a straightforward way to do this that I'm missing? Thanks! Graydon --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus
Wow. Thanks, Rob! That about solves the problem. On Fri, Jul 17, 2015 at 4:01 AM, Rob Stapper <r.stapper@lijbrandt.nl> wrote:
Or, retweeked and made for multiple maps (@ Marc thanx for the inspiration)
declare function XQR.map:merge
( $mapSet as map(*)*
, $mergeFunction as function(*)
) as map(*)
{
fold-left( $mapSet
, map {}
, function( $targetMap
, $sourceMap
)
{
map:merge(( $targetMap
, $sourceMap
, for-each( map:keys( $targetMap)[ . = map:keys( $sourceMap)]
, function( $key
)
{
map:entry( $key
, $mergeFunction( map:get( $targetMap, $key)
, map:get( $sourceMap, $key)
)
)
}
)
))
}
)
} ;
Use:
xqr.map:merge( ( map { 'a' : ( 1,2,3,4)
, 'b' : ( 4,5,6,7)
}
, map { 'b' : ( 6,7,8,9)
, '7' : ( 'x', 'y', 'z')
}
, map { 'b' : ( 9,10,12)
, '7' : ( 'x', 'y', 'p')
}
)
, function( $data1
, $data2
)
{
distinct-values(( $data1, $data2))
}
) ! map:serialize( .)
You’re welcome,
Rob
*Van:* basex-talk-bounces@mailman.uni-konstanz.de [mailto: basex-talk-bounces@mailman.uni-konstanz.de] *Namens *Graydon Saunders *Verzonden:* woensdag 15 juli 2015 20:01 *Aan:* BaseX *Onderwerp:* [basex-talk] Union of maps?
Hi --
In BaseX 8.2.1, I have a bunch of maps; the maps may have some overlap of key values. I would like to merge/find the union of all of these maps while retaining all the values associated with each key in the resulting map-of-all-maps. (Combined map? Any word can be wrong, here! :)
map:merge() doesn't do this; http://docs.basex.org/wiki/Map_Module#map:merge says
"The associated value for each such key is taken from the last map in the input sequence $input that contains an entry with this key." and testing confirms this.
Is there a straightforward way to do this that I'm missing?
Thanks!
Graydon
------------------------------ [image: Avast logo] <https://www.avast.com/antivirus>
Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. www.avast.com <https://www.avast.com/antivirus>
Hi Graydon, here is one more aproach for (it's not so flexible as the functional approach, though): declare function local:merge($maps as map(*)*) as map(*) { map:merge( for $key in distinct-values($maps ! map:keys(.)) return map { $key: ($maps ! .($key)) } ) }; local:merge(( map { 'A': 1, 'B': 2 }, map { 'A': 3, 'C': 4 } )) Cheers, Christian On Wed, Jul 15, 2015 at 8:01 PM, Graydon Saunders <graydonish@gmail.com> wrote:
Hi --
In BaseX 8.2.1, I have a bunch of maps; the maps may have some overlap of key values. I would like to merge/find the union of all of these maps while retaining all the values associated with each key in the resulting map-of-all-maps. (Combined map? Any word can be wrong, here! :)
map:merge() doesn't do this; http://docs.basex.org/wiki/Map_Module#map:merge says "The associated value for each such key is taken from the last map in the input sequence $input that contains an entry with this key." and testing confirms this.
Is there a straightforward way to do this that I'm missing?
Thanks! Graydon
Thank you! Are these easy enough that a map:union() function operating on a sequence of maps isn't something to ask for in the next spec iteration? -- Graydon On Fri, Jul 17, 2015 at 4:18 AM, Christian Grün <christian.gruen@gmail.com> wrote:
Hi Graydon,
here is one more aproach for (it's not so flexible as the functional approach, though):
declare function local:merge($maps as map(*)*) as map(*) { map:merge( for $key in distinct-values($maps ! map:keys(.)) return map { $key: ($maps ! .($key)) } ) };
local:merge(( map { 'A': 1, 'B': 2 }, map { 'A': 3, 'C': 4 } ))
Cheers, Christian
On Wed, Jul 15, 2015 at 8:01 PM, Graydon Saunders <graydonish@gmail.com> wrote:
Hi --
In BaseX 8.2.1, I have a bunch of maps; the maps may have some overlap of key values. I would like to merge/find the union of all of these maps while retaining all the values associated with each key in the resulting map-of-all-maps. (Combined map? Any word can be wrong, here! :)
map:merge() doesn't do this; http://docs.basex.org/wiki/Map_Module#map:merge says "The associated value for each such key is taken from the last map in the input sequence $input that contains an entry with this key." and testing confirms this.
Is there a straightforward way to do this that I'm missing?
Thanks! Graydon
Are these easy enough that a map:union() function operating on a sequence of maps isn't something to ask for in the next spec iteration?
Maybe yes. Feel free to propose it on the W3 issue tracker [1]. The talk@x-query.com mailing list may be another place to discuss this. Best, Christian [1] https://www.w3.org/Bugs/Public/describecomponents.cgi?product=XPath%20%2F%20...
On Fri, Jul 17, 2015 at 4:18 AM, Christian Grün <christian.gruen@gmail.com> wrote:
Hi Graydon,
here is one more aproach for (it's not so flexible as the functional approach, though):
declare function local:merge($maps as map(*)*) as map(*) { map:merge( for $key in distinct-values($maps ! map:keys(.)) return map { $key: ($maps ! .($key)) } ) };
local:merge(( map { 'A': 1, 'B': 2 }, map { 'A': 3, 'C': 4 } ))
Cheers, Christian
On Wed, Jul 15, 2015 at 8:01 PM, Graydon Saunders <graydonish@gmail.com> wrote:
Hi --
In BaseX 8.2.1, I have a bunch of maps; the maps may have some overlap of key values. I would like to merge/find the union of all of these maps while retaining all the values associated with each key in the resulting map-of-all-maps. (Combined map? Any word can be wrong, here! :)
map:merge() doesn't do this; http://docs.basex.org/wiki/Map_Module#map:merge says "The associated value for each such key is taken from the last map in the input sequence $input that contains an entry with this key." and testing confirms this.
Is there a straightforward way to do this that I'm missing?
Thanks! Graydon
talk@x-query.com says "too late for 3.1 (for a two-liner)" which is fair enough. The Michael Kay version of the 2-liner looks like: return map:merge( for $k in distinct-values($maps!map:keys(.)) return map:entry($k, $maps?($k)) ) Your version looks like: map:merge( for $key in distinct-values($maps ! map:keys(.)) return map { $key: ($maps ! .($key)) } ) I feel like I ought to update the docs with one or both but I don't understand the syntax in the return statement of either! Any chance of getting either or both expanded for the easily-bewildered? On Sat, Jul 18, 2015 at 8:19 AM, Christian Grün <christian.gruen@gmail.com> wrote:
Are these easy enough that a map:union() function operating on a sequence of maps isn't something to ask for in the next spec iteration?
Maybe yes. Feel free to propose it on the W3 issue tracker [1]. The talk@x-query.com mailing list may be another place to discuss this.
Best, Christian
[1] https://www.w3.org/Bugs/Public/describecomponents.cgi?product=XPath%20%2F%20...
On Fri, Jul 17, 2015 at 4:18 AM, Christian Grün < christian.gruen@gmail.com> wrote:
Hi Graydon,
here is one more aproach for (it's not so flexible as the functional approach, though):
declare function local:merge($maps as map(*)*) as map(*) { map:merge( for $key in distinct-values($maps ! map:keys(.)) return map { $key: ($maps ! .($key)) } ) };
local:merge(( map { 'A': 1, 'B': 2 }, map { 'A': 3, 'C': 4 } ))
Cheers, Christian
On Wed, Jul 15, 2015 at 8:01 PM, Graydon Saunders <graydonish@gmail.com
wrote:
Hi --
In BaseX 8.2.1, I have a bunch of maps; the maps may have some overlap of key values. I would like to merge/find the union of all of these maps while retaining all the values associated with each key in the resulting map-of-all-maps. (Combined map? Any word can be wrong, here! :)
map:merge() doesn't do this; http://docs.basex.org/wiki/Map_Module#map:merge says "The associated value for each such key is taken from the last map in the input sequence $input that contains an entry with this key." and testing confirms this.
Is there a straightforward way to do this that I'm missing?
Thanks! Graydon
Hi Graydon, The solutions look similar indeed. Here is an more verbose writing, I hope it's helpful? map:merge( (: select distinct keys :) for $key in distinct-values( for $map in $maps return map:keys($map) ) (: create new map entry with all values :) return map { $key : for $map in $maps return $map($key) } ) I recommend you to have a closer look at our Wiki article on XQuery 3.1 [1] and, possibly, XQuery 3.0 [2]. We tried to summarize the new language features in a simple and concise manner. Cheers, Christian [1] http://docs.basex.org/wiki/XQuery_3.1 [2] http://docs.basex.org/wiki/XQuery_3.0
return map:merge( for $k in distinct-values($maps!map:keys(.)) return map:entry($k, $maps?($k)) )
Your version looks like: map:merge( for $key in distinct-values($maps ! map:keys(.)) return map { $key: ($maps ! .($key)) } )
I feel like I ought to update the docs with one or both but I don't understand the syntax in the return statement of either!
Any chance of getting either or both expanded for the easily-bewildered?
On Sat, Jul 18, 2015 at 8:19 AM, Christian Grün <christian.gruen@gmail.com> wrote:
Are these easy enough that a map:union() function operating on a sequence of maps isn't something to ask for in the next spec iteration?
Maybe yes. Feel free to propose it on the W3 issue tracker [1]. The talk@x-query.com mailing list may be another place to discuss this.
Best, Christian
[1] https://www.w3.org/Bugs/Public/describecomponents.cgi?product=XPath%20%2F%20...
On Fri, Jul 17, 2015 at 4:18 AM, Christian Grün <christian.gruen@gmail.com> wrote:
Hi Graydon,
here is one more aproach for (it's not so flexible as the functional approach, though):
declare function local:merge($maps as map(*)*) as map(*) { map:merge( for $key in distinct-values($maps ! map:keys(.)) return map { $key: ($maps ! .($key)) } ) };
local:merge(( map { 'A': 1, 'B': 2 }, map { 'A': 3, 'C': 4 } ))
Cheers, Christian
On Wed, Jul 15, 2015 at 8:01 PM, Graydon Saunders <graydonish@gmail.com> wrote:
Hi --
In BaseX 8.2.1, I have a bunch of maps; the maps may have some overlap of key values. I would like to merge/find the union of all of these maps while retaining all the values associated with each key in the resulting map-of-all-maps. (Combined map? Any word can be wrong, here! :)
map:merge() doesn't do this; http://docs.basex.org/wiki/Map_Module#map:merge says "The associated value for each such key is taken from the last map in the input sequence $input that contains an entry with this key." and testing confirms this.
Is there a straightforward way to do this that I'm missing?
Thanks! Graydon
participants (4)
-
Christian Grün -
Graydon Saunders -
Marc van Grootel -
Rob Stapper