Решение group by
Мартина Хоннена является очевидным и лучшим.Но если вы хотите итеративно заполнять последовательность или массив в XQuery, важно понимать, что ваш подход не может работать на функциональном языке , подобном XQuery, поскольку все переменные являются неизменяемыми.Понимание основ функционального программирования действительно важно, если вы хотите выйти за рамки простых выражений XPath и FLWOR.
"Эквивалентом" итерации в функциональных языках является рекурсия, поэтому здесь есть рекурсивное решение вашей задачи с использованиемопределяемая пользователем функция:
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
, вероятно, всегда побьет его.