3

If the Sequence = [a a b c c c a d d e e e f g h h]

then the Output = [1 2 1 1 2 3 1 1 2 1 2 3 1 1 1 2]

Have tried to use recursion but no luck...Please Help..Thanks in Anticipation

Note: Using XQuery implementation 1.0

One of my failed implementation looks like:

declare function local:test($sequence,$count){

for $counter in (1 to count($sequence))

let $maxIndex := count($sequence)

return

if (matches(subsequence($sequence,1,$maxIndex)[$counter],subsequence($sequence,1,$maxIndex)[$counter + +1])) then let $count := $count + 1 return $count[last()]

else let $count := 1 return $count[last()]


};
Kaushik Bose
  • 71
  • 1
  • 8
  • @tod :Added effort, however actual one looks different as original requirement is somewhat different, but objective is same. – Kaushik Bose Feb 24 '15 at 08:26
  • It seems that as $counter is a sequence hence it returns a sequence in matches condition and hence this implementation fails. – Kaushik Bose Feb 24 '15 at 08:46
  • 1
    Does this sequence come from your input XML? If so, please show this document. – Mathias Müller Feb 24 '15 at 09:24
  • @MathiasMüller this sequence is passed to the function as local:test(data($head1/*:Row/X),1) – Kaushik Bose Feb 24 '15 at 09:49
  • I am asking for the ultimate source of this data. What is inside $head and where does it come from? – Mathias Müller Feb 24 '15 at 09:51
  • 1
    @MathiasMüller $head is a external variable and looks like a1 b1 c1

    extra

    a2 b2 c2

    extra

    a2 b2 c3

    extra

    a2 b2 c4

    extra

    a3 b3 c3

    extra

    – Kaushik Bose Feb 24 '15 at 09:55
  • Have a look at [how to post an SSCCE](http://www.sscce.org). Especially important is to provide your effort, but also what's going wrong (eg. current output or error messages). – Jens Erat Feb 24 '15 at 10:08
  • Xquery being a functional language the implementation itself seems problematic. – Kaushik Bose Feb 24 '15 at 10:14
  • I think you *will* need to use recursion. Please post your attempt using recursion, and maybe we can help you troubleshoot it. – LarsH Feb 24 '15 at 11:02

3 Answers3

4

You are correct, recursion is a very viable way to go here. What the following function does it traverses the sequence from end to start. For each element it then counts in local:count() whether the element before is the same as the current element. If so, it will call the function recursively, otherwise the repetitive sequence ended and 1 is returned.

In the end, this resulting sequence is reversed once again as to match the order of the incoming sequence.

declare function local:count($sequence, $pos) {
  if ($sequence[$pos - 1] = $sequence[$pos])
  then 1 + local:count($sequence, $pos - 1)
  else 1
};

declare function local:test($sequence){
  reverse(
    for $pos in reverse(1 to count($sequence))
    return local:count($sequence, $pos)
  )
};

let $test := ("a","a", "b", "c", "c", "c", "a", "d", "d", "e", "e", "e", "f", "g", "h", "h")
return local:test($test)
dirkk
  • 6,160
  • 5
  • 33
  • 51
  • No it didn't worked: I used Input as : a a b c c c a d d e e e f g h h and Got Output: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 – Kaushik Bose Feb 24 '15 at 12:01
  • You didn't modify anything in the functions `local:count()` or `local:test()`. Seems like you didn't pass a sequence into `local:test()`. – dirkk Feb 24 '15 at 12:47
  • No i passed a sequence, to re-clarify, I again changed the code: http://pastie.org/9980545 and passed a,a,b,c,c,c,a,d,d,e,e,e,f,g,h,h and Got Output: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 – Kaushik Bose Feb 25 '15 at 06:30
  • I am sorry, but your statement is incorrect. If you pass in an xs:string `"a,a,b,c,c,c,a,d,d,e,e,e,f,g,h,h"` into your xs:OutToMod() function you will get the correct result `1 2 1 1 2 3 1 1 2 1 2 3 1 1 1 2`. If not, you are either doing something wrong or your processor is behaving incorrectly. – dirkk Feb 25 '15 at 09:34
  • Ya may be, I am using Xquery engine that comes bundled with Oracle Enterprise Pack for Eclipse (11gR1 - 11.1.1.7.3) and it lacks some functionalities and often deviates from actual W3 recommendation. – Kaushik Bose Feb 25 '15 at 09:39
0

I got a working solution for my Question. Credits: odie_63 @ http://odieweblog.wordpress.com/

declare namespace xf = "http://tempuri.org/OSBTestProject/Resources/XQuery/test/";

declare function local:sequence-group($seq as item()*) as item()*
{
   let $start-of-group :=
   fn:index-of(
     for $i in 1 to count($seq)
     let $prev := $seq[$i - 1]
     return if ($prev != $seq[$i] or not($prev)) then 1 else 0
   , 1
   )
   return
     for $i in 1 to count($seq)
     return $i - $start-of-group[. le $i][last()] + 1
};

declare function xf:test($test as xs:string) as xs:integer*
 {
let $test1 := tokenize($test, ',')
 return  local:sequence-group($test1)
};

declare variable $test as xs:string external;

xf:test($test)

Input: a,a,b,c,c,c,a,d,d,e,e,e,f,g,h,h

Output: 1 2 1 1 2 3 1 1 2 1 2 3 1 1 1 2

Kaushik Bose
  • 71
  • 1
  • 8
0

Not tested, but this should work, and is fairly simple.

declare function local:test($sequence)
{
    for $item at $current-pos in $sequence
    let $different-pos :=
        last((0, $sequence[position() < $current-pos][. != $item]))
    return $current-pos - $different-pos
}
Oliver Hallam
  • 4,242
  • 1
  • 24
  • 30