2017-02-15 54 views
2

假设我有一个列表100字符串元素和我想获得50这些随机文本字符串随机返回。XQuery从列表中获取随机文本

我尝试这样做:

let $list := ("a","b",..."element number 100") 
return xdmp:random(100) 

该查询返回一个字符串,我想回到50回字符串彼此不同。

回答

6

最简单通过xdmp:random()和限制命令到第一50:

(for $x in (1 to 100) 
order by xdmp:random() 
return $x 
)[1 to 50] 
+0

这是一个很好的做法。 –

1

假设它在每次调用返回不同的结果(但我不能从xdmp:random的文件是否是这样说),下面的代码返回从列表中50串随机选出(但不一定是不同的):

let $list := ("a","b",..."element number 100") 
for $i in 1 to 50 
let $position = 1 + xdmp:random(99) 
return $list[$position] 

然而,xdmp:random确切行为,即,它是否在调用返回相同的结果,依赖于发动机MarkLogic如何支持或治疗非确定性的行为,这是XQuery规范的范围之外。严格遵守规范实际上会返回50倍与上述查询相同的结果。

XQuery 3.1提供了一个可以控制种子的random number generator。这允许您通过链接调用来生成尽可能多的数字,而只使用可互操作的行为并保持在完全确定的领域。

编辑:这里是一个查询(仍然假设每次调用xdmp:random)应该确保从grtjn的评论中得到列表中的50个不同的字符串。它使用GROUP BY子句,并依赖于一个懒惰的评价以最初的50

let $list := ("a","b",..."element number 100") 
let $positions := (
    for $i in 1 to 100000 (: can be adjusted to make sure we get 50 distinct :) 
    group by $position = 1 + xdmp:random(count($list) - 1) 
    return $position 
)[position() le 50] 
return $list[position() = $positions] 

我觉得hunterhacker的提案计算$positions是更好不过。

+0

'xdmp:随机(N)'返回0至N,而位置1索引。你需要像'xdmp:random(99)+ 1' – BenW

+0

啊是的,这是一个很好的观点!在XQuery中从0开始有点不同寻常。我已经相应地修正了。 –

2

如果您要说50个字符串必须与另一个不同,那么即使xdmp:random()在同一个查询中重复调用时返回不同的值,同样的名单是不够的,因为可能会有重复。你需要从50个不同的名单中获得随机头寸。

declare function local:pickSomeFromList($some as xs:integer, $listIn as xs:string*, $listOut as xs:string*) as xs:string* { 
    if($some = 0 or not($listIn)) then $listOut 
    else 
    let $random := xdmp:random(count($listIn) - 1) + 1 
    return local:pickSomeFromList(
     $some - 1, 
     ($listIn[fn:position() lt $random],$listIn[fn:position() gt $random]), 
     ($listOut, $listIn[$random]) 
    ) 
}; 
let $list := ("a","b","c","d","e","f","g","h","i","element number 10") 
return local:pickSomeFromList(5, $list,()) 
2

xdmp:random()(以及xdmp:elapsed-time())在每次调用返回不同的值。如果不行的话,这将是相当不切实际的。这与例如fn:current-dateTime()相反,它在整个执行过程中给出相同的值。

Ghislain正在做一次很好的第一次尝试,但BenW也指出,即使xdmp:random()每次都会返回不同的结果,但并不是说它们在整个执行过程中都是唯一的。它的64位最大比例的碰撞很少见(尽管仍然有可能),但在10或100之类的小尺度上,它可能会有一些意外的重复。一旦选择,从列表中删除文本是明智的。

BenW打败了我发布替代Ghislain,它看起来相似,但使用较少的行。无论如何,希望有人发现它有用:

declare function local:getRandomTexts($list, $count) { 
    if ($count > 0 and exists($list)) then 
    let $random := xdmp:random(count($list) - 1) + 1 
    let $text := $list[$random] 
    return ($text, local:getRandomTexts($list[. != $text], $count - 1)) 
    else() 
}; 

let $list := 
    for $i in (1 to 26) 
    return fn:codepoints-to-string(64 + $i) 
for $t in local:getRandomTexts($list, 100) 
order by $t 
return $t 

HTH!

+1

为任何人奇迹[“为什么不只是做$ list [xdmp:random(count($ list) - 1)+ 1]”](http://blog.davidcassel.net/2010/07/gotcha - 次序指数评价/)? –