我认为标准化的random-numer-generator 函数及其permute 函数(https://www.w3.org/TR/xpath-functions/#func-random-number-generator)应该会给你更好的“随机性”和多样化的结果,例如
let $file-count := count($data)
return $data[position() = random-number-generator(current-dateTime())?permute(1 to $file-count)[position() le 4]]
我还没有在您的 db/XQuery 实现中尝试过,您当前使用的功能可能还有其他方法。
对于 eXist-db,我想一种策略是调用 random-number 函数,直到您获得所需值数量的不同序列,以下返回(至少在使用 eXide 的某些测试中))四个不同的数字每次通话 1 和 40:
declare function local:random-sequence($max as xs:integer, $length as xs:integer) as xs:integer+ {
local:random-sequence((), $max, $length)
};
declare function local:random-sequence($seq as xs:integer*, $max as xs:integer, $length as xs:integer) as xs:integer+ {
if (count($seq) = $length and $seq = distinct-values($seq))
then $seq
else local:random-sequence((distinct-values($seq), util:random($max)), $max, $length)
};
let $file-count := 40
return local:random-sequence($file-count, 4)
在之前的尝试中整合它会导致
let $file-count := count($data)
return $data[position() = local:random-sequence($file-count, 4)]
至于您的评论,我没有注意到存在 util:random 函数可以返回 0 并排除最大值,因此根据您的评论和进一步的测试,我猜您希望我上面发布的函数被实现为
declare function local:random-sequence($seq as xs:integer*, $max as xs:integer, $length as xs:integer) as xs:integer+ {
if (count($seq) = $length)
then $seq
else
let $new-number := util:random($max + 1)
return if ($seq = $new-number or $new-number = 0)
then local:random-sequence($seq, $max, $length)
else local:random-sequence(($seq, $new-number), $max, $length)
};
这样,它现在有望返回 $length 和 1 和 $max 参数之间的不同值。