XQuery从列表中获取随机文本

时间:2017-02-15 12:59:06

标签: list xquery marklogic

假设我有一个 100 String 元素列表,我希望随机返回 50个随机文本字符串

我尝试这样做:

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

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

4 个答案:

答案 0 :(得分:6)

最容易按xdmp:random()订购并限制为前50:

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

答案 1 :(得分:3)

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!

答案 2 :(得分: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, ())

答案 3 :(得分: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]

我认为猎人的计算$positions的建议甚至更好。