majic
majic

Reputation: 13

Xquery result duplicated

I'm not getting the output I want. I don't understand why the result is duplicated. Can someone help me?

for $i in 1 to 2
let $rng:=random-number-generator()
let $rng1:=$rng('permute')(1 to 10)

let $rng:=$rng('next')()
let $rng2:=$rng('permute')(1 to 10)

let $rng:=$rng('next')()
let $rng3:=$rng('permute')(1 to 10)

return (string-join($rng1),string-join($rng2),string-join($rng3),",")

result:
23496815107
31018674529
31017684259

23496815107
31018674529
31017684259

Upvotes: 1

Views: 159

Answers (3)

Michael Kay
Michael Kay

Reputation: 163342

The specification is here:

http://www.w3.org/TR/xpath-functions-31/#func-random-number-generator

It says:

Both forms of the function are ·deterministic·: calling the function twice with the same arguments, within a single ·execution scope·, produces the same results.

If you supply $i as the $seed argument to random-number-generator then the two sequences should be different.

Upvotes: 1

Ghislain Fourny
Ghislain Fourny

Reputation: 7279

I think I now understand what confuses you in this original query. One could indeed expect the random numbers to be generated differently for each iteration of $i.

However, XQuery is (to put it simply, with a few exceptions) deterministic. This means that the random generator probably gets initialized in each iteration with the same, default seed.

Thus, I have a second potential answer:

If you have a way to pass a different seed to $rng, you could slightly modify your initial query by constructing a seed based on $i and maybe current-dateTime() in each iteration before generating the numbers. But it will still be the same if you execute the query several times unless you involve the current date/time.

Upvotes: 0

Ghislain Fourny
Ghislain Fourny

Reputation: 7279

The result is duplicated because of the initial for $i in 1 to 2, and because the variable $i is not actually used anywhere.

I edited the query based on your comment (getting 10 numbers). From what I understand, the difficulty here is to chain the calls (alternating between 'next' and 'permute'). Chaining calls can be done with a tail recursion.

declare function local:multiple-calls(
        $rng as function(*),
        $number-of-times as xs:integer) as item()* {
  if($number-of-times le 0)
  then ()
  else
      let $rng := $rng('next')
      return ($rng('permute')(1 to 10),
              local:multiple-calls($rng, $number-of-times - 1))
};

local:multiple-calls(random-number-generator(), 10)

Note: I am not sure if (1 to 10) is what needs to actually be passed to the call to $rng('permute'), or if it was an attempt to output ten numbers. In doubt, I haven't changed it.

Upvotes: 1

Related Questions