xQuery - заполнить пользовательский массив - PullRequest
0 голосов
/ 10 декабря 2018

Я получил некоторый набор данных с рекламой разных компаний.

, например

<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

как-то не работает, и я как-то застрял, выясняя, почему ...

Ответы [ 2 ]

0 голосов
/ 11 декабря 2018

Решение 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, вероятно, всегда побьет его.

0 голосов
/ 10 декабря 2018

Пример группировки учебников:

<jobs>
{
    for $job in jobs/job
    group by $company := $job/company
    return $job[1]
}
</jobs>

https://xqueryfiddle.liberty -development.net / b4GWVb

...