Wow—this generated much more discussion than I anticipated.
For my requirements of the moment the order of the result node set is
unimportant, so “$nodes intersect ()” seems like the least surprising solution
(and I suspect I might have arrived at it if I’d spent a bit more time thinking
about the problem, but it’s the holidays and I had things to do and places to
be …).
I’ve never actually taken the time to understand how fold-left works, so this
is an opportunity to learn.
From the functions and operators spec:
<lq>
Fold-left
Processes the supplied sequence from left to right, applying the supplied
function repeatedly to each item in turn, together with an accumulated result
value.
</lq>
So given this expression:
fold-left($nodes, (), function($a, $n) { $a, $n except $a })
I understand this to be iterating over $nodes from left to right, applying the
function function($a, $n) to each node, where $a is the next node and $n is the
accumulated value (being the result returned by the function on each
invocation).
The “$a, $n except $a” in the function body constructs a new sequence of ($a,
$n), excluding $a if it is already in $n. This sequence is then passed as the
second parameter of the next invocation of the function. This has the effect of
preserving the order of input node list.
If I have this right then it’s essentially equivalent to my original recursive
solution but much, much simpler and of course usable directly as an XPath
expression.
Cheers,
E.
_____________________________________________
Eliot Kimber
Sr Staff Content Engineer
O: 512 554 9368
M: 512 554 9368
servicenow.com<https://www.servicenow.com>
LinkedIn<https://www.linkedin.com/company/servicenow> |
Twitter<https://twitter.com/servicenow> |
YouTube<https://www.youtube.com/user/servicenowinc> |
Facebook<https://www.facebook.com/servicenow>
From: Michael Kay mike(_at_)saxonica(_dot_)com
<xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com>
Date: Wednesday, December 29, 2021 at 4:37 AM
To: xsl-list <xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>
Subject: Re: [xsl] XQuery/XPath 3.1: Node List to Node Set ("distinct nodes")
[External Email]
Here is an improved (and shorter) version of the fold-left() solution:
fold-left($nodes, (), function($a, $n) { $a, $n except $a })
Michael Kay
Saxonica
On 28 Dec 2021, at 23:47, Michael Kay
mike(_at_)saxonica(_dot_)com<mailto:mike(_at_)saxonica(_dot_)com>
<xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com<mailto:xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com>>
wrote:
For a solution that delivers distinct nodes in order of first appearance, my
preference would be
$nodes => fold-left((), function($all, $this) {if ($all intersect $this) then
$all else ($all, $this)})
It's likely to be O(n^2) in most implementations, whereas Martin Honnen's
solution is probably O(n log n) -- but this one is XPath rather than XQuery,
and feels more elegant.
Michael Kay
Saxonica
--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--