xQuery - 填充自定义数组
xQuery - fill custom array
我得到了一些包含不同公司广告的数据集。
例如
<jobs>
<job>
<company>A</company>
<value>Testvalue</value>
</job>
<job>
<company>A</company>
<value>Testvalue</value>
</job>
<job>
<company>B</company>
<value>Testvalue</value>
</job>
<job>
<company>C</company>
<value>Testvalue</value>
</job>
</jobs>
我想做的是生成自定义输出。我想每个公司只有 1 条记录
需要示例输出:
<jobs>
<job>
<company>A</company>
<value>Testvalue</value>
</job>
<job>
<company>B</company>
<value>Testvalue</value>
</job>
<job>
<company>C</company>
<value>Testvalue</value>
</job>
</jobs>
我试过的是:
如果公司不在数组中,则将其追加到一个数组并将该项目追加到另一个数组。
(: loop through job in jobs :)
for $ad in //jobs/job
(: firmenarray, "unique" ads :)
let $companys := ()
let $ads := ()
(: declare company of ad:)
let $company := $ad//company[1]
(: if ad/company not within companyarray > add & concat to ads :)
let $test := if(not(fn:index-of($companys, $company))) then(
(: add ad/company to companys :)
$companys = fn:insert-before($companys, 0, $company),
(: add jobs/job to ads :)
$ads = fn:insert-before($ads, 0, $ad)
)
return $ads
不知何故,它不起作用,我有点卡住找出原因...
教科书分组示例:
<jobs>
{
for $job in jobs/job
group by $company := $job/company
return $job[1]
}
</jobs>
Martin Honnen 的 group by
解决方案是显而易见的最佳解决方案。但是,如果您想在 XQuery 中迭代填充序列或数组,那么了解您的方法 无法在像 XQuery 这样的 functional language 中工作 很重要,因为所有变量都是不可变的.如果您想超越简单的 XPath 和 FLWOR 表达式,了解函数式编程的基础知识非常重要。
函数式语言中的 "equivalent" 迭代是递归,因此这里是使用用户定义函数的递归解决方案:
declare function local:unique($companies, $unique) {
if(empty($companies)) then $unique
else if($companies[1]/company = $unique/company)
then local:unique(tail($companies), $unique)
else local:unique(tail($companies), ($unique, $companies[1]))
};
<jobs>{
local:unique(/jobs/job, ())
}</jobs>
这种遍历序列并聚合结果的特定模式非常普遍,甚至被抽象成自己的标准函数,即 fn:fold-left($sequence, $start-value, $aggregation-function)
。在它的帮助下,解决方案变得非常简短:
<jobs>{
fn:fold-left(/jobs/job, (), function($companies, $company) {
if($company/company = $companies/company) then $companies
else ($companies, $company)
})
}</jobs>
但是由于您将每个新条目与所有以前找到的唯一公司条目进行比较,因此该解决方案仍然效率很低。实施良好的 group by
可能总能击败它。
我得到了一些包含不同公司广告的数据集。
例如
<jobs>
<job>
<company>A</company>
<value>Testvalue</value>
</job>
<job>
<company>A</company>
<value>Testvalue</value>
</job>
<job>
<company>B</company>
<value>Testvalue</value>
</job>
<job>
<company>C</company>
<value>Testvalue</value>
</job>
</jobs>
我想做的是生成自定义输出。我想每个公司只有 1 条记录
需要示例输出:
<jobs>
<job>
<company>A</company>
<value>Testvalue</value>
</job>
<job>
<company>B</company>
<value>Testvalue</value>
</job>
<job>
<company>C</company>
<value>Testvalue</value>
</job>
</jobs>
我试过的是:
如果公司不在数组中,则将其追加到一个数组并将该项目追加到另一个数组。
(: loop through job in jobs :)
for $ad in //jobs/job
(: firmenarray, "unique" ads :)
let $companys := ()
let $ads := ()
(: declare company of ad:)
let $company := $ad//company[1]
(: if ad/company not within companyarray > add & concat to ads :)
let $test := if(not(fn:index-of($companys, $company))) then(
(: add ad/company to companys :)
$companys = fn:insert-before($companys, 0, $company),
(: add jobs/job to ads :)
$ads = fn:insert-before($ads, 0, $ad)
)
return $ads
不知何故,它不起作用,我有点卡住找出原因...
教科书分组示例:
<jobs>
{
for $job in jobs/job
group by $company := $job/company
return $job[1]
}
</jobs>
Martin Honnen 的 group by
解决方案是显而易见的最佳解决方案。但是,如果您想在 XQuery 中迭代填充序列或数组,那么了解您的方法 无法在像 XQuery 这样的 functional language 中工作 很重要,因为所有变量都是不可变的.如果您想超越简单的 XPath 和 FLWOR 表达式,了解函数式编程的基础知识非常重要。
函数式语言中的 "equivalent" 迭代是递归,因此这里是使用用户定义函数的递归解决方案:
declare function local:unique($companies, $unique) {
if(empty($companies)) then $unique
else if($companies[1]/company = $unique/company)
then local:unique(tail($companies), $unique)
else local:unique(tail($companies), ($unique, $companies[1]))
};
<jobs>{
local:unique(/jobs/job, ())
}</jobs>
这种遍历序列并聚合结果的特定模式非常普遍,甚至被抽象成自己的标准函数,即 fn:fold-left($sequence, $start-value, $aggregation-function)
。在它的帮助下,解决方案变得非常简短:
<jobs>{
fn:fold-left(/jobs/job, (), function($companies, $company) {
if($company/company = $companies/company) then $companies
else ($companies, $company)
})
}</jobs>
但是由于您将每个新条目与所有以前找到的唯一公司条目进行比较,因此该解决方案仍然效率很低。实施良好的 group by
可能总能击败它。