Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

array:values (resolved: map:values, map:entries) #29

Closed
ChristianGruen opened this issue Dec 18, 2020 · 12 comments
Closed

array:values (resolved: map:values, map:entries) #29

ChristianGruen opened this issue Dec 18, 2020 · 12 comments
Labels
Feature A change that introduces a new feature XQFO An issue related to Functions and Operators

Comments

@ChristianGruen
Copy link
Contributor

ChristianGruen commented Dec 18, 2020

EDIT: Revised and aligned with the recently added and proposed map and array functions (#314, #357):

The suggested functions are based on the observations that:

  • users who prefer readable function names tend to reject ?* as handy shortcut;
  • functions are often more flexible and better composable than FLWOR enhancements (but of course both could be added).

array:values

Summary

Returns all members of an array as a sequence. Equivalent to $array?*, but better composable and easier to read (especially for newcomers), and known from other programming languages.

Signature

array:values($array as array(*)) as item()*

Example

(: Query :)
let $array := [ (), 2, [ 3, 4 ] ]
return array:values($array)

(: Result :)
2
[ 3, 4 ]

map:values

Summary

Returns all values of a map as a sequence. Complementary to map:keys, and equivalent to $map?*, but better composable and easier to read (especially for newcomers), and known from other programming languages.

Signature

map:values($map as map(*)) as item()*

Example

(: Query :)
let $map := map { 'a': (), 'b': 2, 'c': [ 3, 4 ] }
return map:values($map)

(: Result :)
2
[ 3, 4 ]

map:entries

See #357 on composing and decomposing Key-Value Records.

Summary

Returns each entry of a map as a singleton map. Equivalent to map:for-each($map, map:entry#2).

Signature

map:entries($map as map(*)) as map(*)*

Example

(: Query :)
let $map := map { 'a': (), 'b': 2, 'c': [ 3, 4 ] }
for $entry in map:entries($map)
return element { map:keys($entry) } { string-join(map:values($entry)) }

(: Result :)
<a/>
<b>2</b>
<c>34</c>

array:members

See #314.

@rhdunn
Copy link
Contributor

rhdunn commented Dec 18, 2020

It may be more useful to have map:entries equivalent to:

map:for-each($map, function($key, $value) {
  map { "key": $key, "value": $value }
})

as that is more composable with things like the lookup operator, and would be more similar to how the function works in other languages.

@ChristianGruen
Copy link
Contributor Author

True, that would certainly be the better solution. The updated example:

(: Query :)
let $map := map { 'a': (), 'b': 2, 'c': [ 3, 4 ] }
for $entry in map:entries($map)
return element { $entry?key } { string-join($entry?value) }

@michaelhkay
Copy link
Contributor

michaelhkay commented Aug 11, 2022

The xsl:map-entry instruction creates a singleton map which it represents as map{$key : $value}, rather than map{"key":$key, "value":$value}. Both representations have their advantages and disadvantages, but I think construction and deconstruction should be symmetric, so I think map:entries() should return the first form rather than the second. The main advantage of this form is that you can reconstruct the map from selected entries using map:merge() (or xsl:map).

The main disadvantage of the first form is how to extract the key and value. (The second form enables $entry?key and $entry?value.) You can get the key using map:keys(), though the plural name is unhelpful, and you can get the value using the proposed map:values().

@michaelhkay
Copy link
Contributor

The array:members() suggested here is similar to the array:members or array:parcels proposed in #113 with the representation of a "parcel" being an array. Representing a parcel as an array is one of the options in that proposal, but it's not my preferred option, partly because I think the result is quite confusing to users, and partly because it doesn't work well for processing arrays using xsl:apply-templates - it's difficult to define match patterns to match the parcels.

@michaelhkay
Copy link
Contributor

While there are use cases for map:values() in some form, it's not clear what it should return in the case where the map entries are sequences. Concatenating the sequences seems to give a result that's unlikely to be useful. Returning a sequence of parcels retains more information, but that's not helpful in the common case where the values are known to be single items. It's always possible to do either using for example map:for-each(->($k,$v){$v)) or map:for-each(->($k,$v){parcel($v)}. So perhaps concatenating the sequences is OK.

@michaelhkay
Copy link
Contributor

Perhaps there's a case for having both map:entries() returning a sequence of singleton maps (map{$key : $value}) and map:key-value-pairs() returning a sequence of maps in the form map{"key": $key, "value": $value}.

@ChristianGruen
Copy link
Contributor Author

I think map:entries() should return the first form rather than the second.

Yes, I had similar thoughts. The simpler representation would equal the initial proposal in this issue.

While there are use cases for map:values() in some form, it's not clear what it should return in the case where the map entries are sequences.

I would basically regard it as functional alternative for the two-character wildcard lookup (?*):

(//country ! map:entry(name, number(@population)))
=> map:merge()
=> map:filter(function($k, $v) { $v > 1000000 })
=> map:values()

@rhdunn
Copy link
Contributor

rhdunn commented Aug 11, 2022

I'm happy with the suggested change to map:entries and the proposed map:key-value-pairs function.

@benibela
Copy link

map:key-value-pairs() returning a sequence of maps in the form map{"key": $key, "value": $value}.

If it would return an array [$key, $value], it would probably have better performance

@ndw ndw added the XQFO An issue related to Functions and Operators label Sep 14, 2022
@ChristianGruen ChristianGruen added this to the QT 4.0 milestone Oct 14, 2022
@benibela
Copy link

benibela commented Dec 29, 2022

Real-life example I got per mail where map:entries could be useful:

Input: A movie from a movie database (simplified): {"ACTOR1": "..name:", "ACTOR2": "..name.", "DIRECTOR": ".."}

Task: Get the name of all actors, a sequence of strings.

He wrote: ?*[?contains(name(),'ACTOR')] and wants to know why that does not work

@ChristianGruen ChristianGruen changed the title [FO] array:members, map:entries, array:values, map:values [FO] map:values, array:values, map:entries Apr 4, 2023
@ChristianGruen
Copy link
Contributor Author

I have revised and aligned the issue with the recently added and proposed map and array functions (#314, #357).

michaelhkay added a commit to michaelhkay/qtspecs that referenced this issue Apr 19, 2023
@ChristianGruen ChristianGruen changed the title [FO] map:values, array:values, map:entries [FO] array:values (resolved: map:values, map:entries) Apr 27, 2023
@ChristianGruen
Copy link
Contributor Author

For map:entries and map:values, a function has been added in #449.

I’ll keep the issue open for array:values.

@ChristianGruen ChristianGruen added the Feature A change that introduces a new feature label Apr 27, 2023
@ChristianGruen ChristianGruen removed this from the QT 4.0 milestone Apr 27, 2023
@ChristianGruen ChristianGruen changed the title [FO] array:values (resolved: map:values, map:entries) array:values (resolved: map:values, map:entries) Apr 27, 2023
@ChristianGruen ChristianGruen self-assigned this May 5, 2023
ChristianGruen added a commit to ChristianGruen/qtspecs that referenced this issue May 7, 2023
@ChristianGruen ChristianGruen removed their assignment Mar 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature A change that introduces a new feature XQFO An issue related to Functions and Operators
Projects
None yet
Development

No branches or pull requests

5 participants