<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://www.w3.org/Bugs/Public/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.4"
          urlbase="https://www.w3.org/Bugs/Public/"
          
          maintainer="sysbot+bugzilla@w3.org"
>

    <bug>
          <bug_id>19158</bug_id>
          
          <creation_ts>2012-10-01 09:53:45 +0000</creation_ts>
          <short_desc>[XT30] Getting all values from a map</short_desc>
          <delta_ts>2014-05-15 14:00:44 +0000</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>1</classification_id>
          <classification>Unclassified</classification>
          <product>XPath / XQuery / XSLT</product>
          <component>XSLT 3.0</component>
          <version>Working drafts</version>
          <rep_platform>All</rep_platform>
          <op_sys>All</op_sys>
          <bug_status>CLOSED</bug_status>
          <resolution>FIXED</resolution>
          
          
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords></keywords>
          <priority>P2</priority>
          <bug_severity>normal</bug_severity>
          <target_milestone>---</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter name="Jakub Maly">jakub</reporter>
          <assigned_to name="Michael Kay">mike</assigned_to>
          
          
          <qa_contact name="Mailing list for public feedback on specs from XSL and XML Query WGs">public-qt-comments</qa_contact>

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>74914</commentid>
    <comment_count>0</comment_count>
    <who name="Jakub Maly">jakub</who>
    <bug_when>2012-10-01 09:53:45 +0000</bug_when>
    <thetext>To get all values from a map as a single sequence I write 
for $k in map:keys($mymap) return $mymap($k) 
which is long and also probably ineffective (O(NlogN)?)

I propose to add a function 
map:values($mymap)

which would return all values from a map as a sequence. Unlike the code above, it could be implemented in O(N). 


Also, when I have a map entry (a map containing one item) in variable $entry,
I can write map:keys($entry) to get the key of the entry. 
To get the value, I must write 
$entry(map:keys($entry)), which is a bit convoluted and could be replaced by 
map:values($entry).</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>74932</commentid>
    <comment_count>1</comment_count>
    <who name="Michael Kay">mike</who>
    <bug_when>2012-10-01 16:53:43 +0000</bug_when>
    <thetext>A problem with map:values() is that in the general case it would return a sequence of sequences, which we can&apos;t represent (except as a map...). Flattening it wouldn&apos;t produce anything useful. The function could be useful in the special case where the values are all singletons, but I&apos;m not sure we really want to specify it to work in that case and fail in other cases.

Another approach is to define map:entries which returns a sequence of &quot;pairs&quot;, each pair being a map with two entries, accessible via the keys &quot;key&quot; and &quot;value&quot;.

The reason we didn&apos;t put anything like this in the spec is that we weren&apos;t comfortable with any of the designs. Some members wanted to add &quot;tuples&quot; to the model, but we had a lack of consensus as to what they should look like (in particular, whether the components of a tuple should be named or numbered).</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>74935</commentid>
    <comment_count>2</comment_count>
    <who name="Jakub Maly">jakub</who>
    <bug_when>2012-10-01 17:32:45 +0000</bug_when>
    <thetext>Oh, I forgot about the nested sequences again... 

There may be no nice solution, but at least some solution should be available. 

When I write 
&lt;xsl:for-each select=&quot;$mymap&quot;&gt;

then &quot;.&quot; returns a 1-item map in each entry, which is near to the &quot;map:entries&quot; solution. However, I still have to write (.)(map:keys(.)) to get the value.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>75626</commentid>
    <comment_count>3</comment_count>
    <who name="Jakub Maly">jakub</who>
    <bug_when>2012-10-08 20:43:57 +0000</bug_when>
    <thetext>How about using higher-order functions to solve this. 

Let&apos;s say there is map:process HOF and it uses an accumulator to store intermediate results, the accumulator is initialized using the last parameter and the value of the accumulator is returned after the last entry was processed. 

For returning all values as one (flattened) sequence:

map:process($mymap, function($key,$value,$acc,()) { $acc, $value })

When someone wants to handle values, which can be sequences or maps, (s)he can use more sophisticated function and accumulator structure. 

My only concern is whether calling $acc, $value would be effective (linear)?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>75638</commentid>
    <comment_count>4</comment_count>
    <who name="Michael Kay">mike</who>
    <bug_when>2012-10-08 22:30:43 +0000</bug_when>
    <thetext>I think the idea of a map:process() calling a user-supplied function with two arguments - key and value - makes good sense; effectively a mapping function applied to the entries in a map. I can&apos;t see a good use case for a &quot;fold&quot; (or accumulator) capability here, since the order of processing would be undefined, and aggregation across the entries in a map isn&apos;t an especially common use case.

The flattened set of values could be achieved simply with

map:process($map, function($k, $v){$v})

Conversion to an element structure would look like this:

&lt;xsl:function name=&quot;f:pair&quot;&gt;
  &lt;xsl:param name=&quot;key&quot;/&gt;
  &lt;xsl:param name=&quot;value&quot;/&gt;
  &lt;pair key=&quot;{$key}&quot; value=&quot;{$value}&quot;/&gt;
&lt;/xsl:function&gt;

map:process($map, f:pair#2)

Feels good.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>82966</commentid>
    <comment_count>5</comment_count>
    <who name="Michael Kay">mike</who>
    <bug_when>2013-02-12 10:23:38 +0000</bug_when>
    <thetext>The WG is proposing to add a map:fold function that takes as argument a callback function which is called once for each entry in the map, with three arguments: an accumulator value, and the key and value from the map entry.

Noted that this could be used to implement various other functions including ones we already have such as map:keys() and new functions such as map:values() which returns the flattened values.

Also noted that in principle map:fold could be implemented in terms of fn:fold-left applied to the map:keys() sequence.

Use cases include grouping the entries in the map.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>87168</commentid>
    <comment_count>6</comment_count>
    <who name="Michael Kay">mike</who>
    <bug_when>2013-05-02 14:16:02 +0000</bug_when>
    <thetext>We decided to accept your suggestion of using a higher-order function. We looked at the possibility of a fold()-like function, but decided that a simple mapping function would do the job:

map:for-each-entry(map, function(key, value) =&gt; item()*)

There&apos;s been a decision to rename fn:map as fn:for-each, so this fits in. There&apos;s also some discussion going on about the order of parameters for fn:map() and fn:map-pairs and we&apos;ll look at aligning with the final outcome on those.

Pleae close if this resolution is acceptable.</thetext>
  </long_desc>
      
      

    </bug>

</bugzilla>