XQuery 从列表中获取随机文本
XQuery get Random Text from a List
假设我有一个包含 100 个字符串 元素的列表,我想得到 50 个这些随机文本字符串 为 return 随机编辑。
我尝试这样做:
let $list := ("a","b",..."element number 100")
return xdmp:random(100)
这个查询return一个字符串,我想return返回50个互不相同的字符串。
假设它return每次调用都有不同的结果(但我无法从xdmp:random
的文档中判断是否是这种情况),以下代码returns 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
的确切行为,即它是否 return 跨调用的结果相同,取决于 MarkLogic 引擎如何支持或处理非确定性行为,这不在XQuery 规范的范围。严格遵守规范实际上 return 与上述查询相同的结果的 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
的建议甚至更好。
如果您说 50 个字符串必须彼此不同,例如,不允许重复,那么即使 xdmp:random() 在相同的重复调用时会 return 不同的值查询,在同一个列表中获得 50 个随机位置是不够的,因为可能会有重复。您需要从 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, ())
xdmp:random()
(以及 xdmp:elapsed-time()
)return 每次调用时的不同值。如果不这样做,那将是相当不切实际的。这与例如 fn:current-dateTime()
相反,它在一次执行中给出相同的值 运行.
Ghislain 的第一次尝试很好,但正如 BenW 所指出的那样,即使 xdmp:random()
每次都会 return 不同的结果,但并不是说它们在整个执行过程中都是唯一的 运行。其 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!
最容易订购 xdmp:random()
且仅限前 50 个:
(for $x in (1 to 100)
order by xdmp:random()
return $x
)[1 to 50]
假设我有一个包含 100 个字符串 元素的列表,我想得到 50 个这些随机文本字符串 为 return 随机编辑。
我尝试这样做:
let $list := ("a","b",..."element number 100")
return xdmp:random(100)
这个查询return一个字符串,我想return返回50个互不相同的字符串。
假设它return每次调用都有不同的结果(但我无法从xdmp:random
的文档中判断是否是这种情况),以下代码returns 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
的确切行为,即它是否 return 跨调用的结果相同,取决于 MarkLogic 引擎如何支持或处理非确定性行为,这不在XQuery 规范的范围。严格遵守规范实际上 return 与上述查询相同的结果的 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
的建议甚至更好。
如果您说 50 个字符串必须彼此不同,例如,不允许重复,那么即使 xdmp:random() 在相同的重复调用时会 return 不同的值查询,在同一个列表中获得 50 个随机位置是不够的,因为可能会有重复。您需要从 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, ())
xdmp:random()
(以及 xdmp:elapsed-time()
)return 每次调用时的不同值。如果不这样做,那将是相当不切实际的。这与例如 fn:current-dateTime()
相反,它在一次执行中给出相同的值 运行.
Ghislain 的第一次尝试很好,但正如 BenW 所指出的那样,即使 xdmp:random()
每次都会 return 不同的结果,但并不是说它们在整个执行过程中都是唯一的 运行。其 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!
最容易订购 xdmp:random()
且仅限前 50 个:
(for $x in (1 to 100)
order by xdmp:random()
return $x
)[1 to 50]