Thank you, Leonard. I also thought of the window clause. As for the fold-left, is it a way to express what could also be written as a recursive function?
Il giorno 29 gen 2017, alle ore 13:03, Leonard Wörteler leonard.woerteler@uni-konstanz.de ha scritto:
Hi Joseph,
if the equal elements are always grouped together, you can use the `window` clause to gather them into a window and then iterate over that to get the numbers:
let $src:= <c> <a>red</a> <a>red</a> <a>blue</a> <a>green</a> <a>green</a> </c> for tumbling window $window in $src/* start $s when true() end next $n when $s/text() ne $n/text() for $elem at $pos in $window return <a n="{$pos}">{$elem/node()}</a>
For full control over the state you want to maintain during the iteration, you can use `fn:fold-left` and pass around a map in which you count how often you've encountered each distinct value:
let $src:= <c> <a>red</a> <a>red</a> <a>blue</a> <a>green</a> <a>green</a> </c> return tail( fold-left( $src/*, map{}, function($acc, $a) { let $key := $a/string(), $nums := $acc[1], $n := ($nums($key), 0)[1] + 1 return ( map:merge(($nums, map{ $key: $n })), tail($acc), <a n="{$n}">{$key}</a> ) } ) )
One element element at a time is added to the accumulator, which consists of the map of counts followed by all elements to be output.
Hope that helps, Leo
On 29.01.2017 at 09:50, meumapple wrote (with possible deletions):
Thanks to all of you. The group by clause works, while Andy's solution does not seem to produce the right result on my machine. The group by clause, however, moves the elements for the grouping. I was wondering whether it would be possible to count them without moving, and more in general if there is a way to get more control over 2 for-loops combined, so that once a condition is satisfied it is possible to stop a certain repetition.
Thanks! Joseph
Il giorno 27 gen 2017, alle ore 12:33, Andy Bunce <bunce.andy@gmail.com mailto:bunce.andy@gmail.com> ha scritto:
Hi Joseph, You could see how XQuery update (http://docs.basex.org/wiki/Update) performs...
let $src:=<c> <a>red</a> <a>red</a> <a>blue</a> <a>green</a> <a>green</a>
</c>
return copy $result:=$src modify ( for $a in $result/a return insert node attribute { 'n' } { 1+count($a/preceding-sibling::a[.=$a])} into $a) return $result
/Andy
On 27 January 2017 at 11:23, Marco Lettere <m.lettere@gmail.com mailto:m.lettere@gmail.com> wrote:
Hi Joseph, what about this?
let $input :=
<c> <a>red</a> <a>red</a> <a>blue</a> <a>green</a> <a>green</a> </c>
return <c>{ for $a in $input/* let $t := $a/text() group by $t return for $a2 at $pos in $a return <a n="{$pos}">{$a2/text()}</a> }</c>
Ciao, M.
On 27/01/2017 09:08, meumapple wrote:
Hi, I have a structure like this: <c> <a>red</a> <a>red</a> <a>blue</a> <a>green</a> <a>green</a> </c> And I would like to get: <c> <a n="1">red</a> <a n="2">red</a> <a n="1">blue</a> <a n="1">green</a> <a n="2">green</a> </c> I have tried with two for loops after having identified the distinct-values(). This is in principle correct but it takes too long (I have many distinct values and a elements), because I cannot exit the for loop as soon as I get a match. I have been able to get the result with the window clause and then counting the elements of the window with a nested for-loop: is there an alternative solution? Thanks. Joseph