Как сгруппировать значения по нескольким полям и отсортировать их по заданному типу c - PullRequest
1 голос
/ 02 апреля 2020

Я пытаюсь сгруппировать массив объектов на основе указанного c поля (значения), а затем отсортировать их по определенным c типам:

var list = [
    {value: 'fox', country: 'nl', type: 'animal', priority: 1},
  {value: 'fox', country: 'be', type: 'animal', priority: 2},
  {value: 'cat', country: 'de', type: 'animal', priority: 3},
  {value: 'david', country: 'nl', type: 'human', priority: 4},
  {value: 'marc', country: 'be', type: 'human', priority: 5},
  {value: 'lola', country: 'de', type: 'human', priority: 6},
  {value: 'tiger', country: 'nl', type: 'animal', priority: 7},
  {value: 'koala', country: 'be', type: 'animal', priority: 8},
  {value: 'tiger', country: 'nl', type: 'animal', priority: 9},
];

// output/result should be:
[
  {value: 'fox', countries: ['nl', 'be'], type: 'animal', priority: 1},
  {value: 'cat', countries: ['de'], type: 'animal', priority: 2},
  {value: 'tiger', countries: ['nl'], type: 'animal', priority: 3},
  {value: 'koala', contries: ['be'], type: 'animal', priority: 4},
  {value: 'david', contries: ['nl'], type: 'human', priority: 1},
  {value: 'marc', contries: ['be'], type: 'human', priority: 2},
  {value: 'lola', contries: ['de'], type: 'human', priority: 3},
];

Я пытаюсь редуктор для удаления дубликатов, но мне не удается сгруппировать страны

list.reduce((accumulator, currentValue, index) => {
    const {country, value} = currentValue;
  if(!accumulator.some(item => item.value === currentValue.value)) {
     accumulator.push({
      value: currentValue.value,
      countries: [accumulator.country].concat(currentValue.country)
    })
  }

  return accumulator;
}, [])

Ответы [ 3 ]

0 голосов
/ 02 апреля 2020

Вам нужно три прохода

  • , группировать по требуемому ключу и значениям
  • сортировать массив
  • обновить prioritiey свойство.

function groupBy(data, key, ...values) {
    return Object.values(data.reduce((r, o) => {
        r[o[key]] = r[o[key]] || { ...o, ...Object.fromEntries(values.map(k => [k, []])) };
        values.forEach(k => r[o[key]][k].push(o[k]));
        return r;
    }, {}));
}

var list = [{ value: 'fox', country: 'nl', type: 'animal', priority: 1 }, { value: 'fox', country: 'be', type: 'animal', priority: 2 }, { value: 'cat', country: 'de', type: 'animal', priority: 3 }, { value: 'david', country: 'nl', type: 'human', priority: 4 }, { value: 'marc', country: 'be', type: 'human', priority: 5 }, { value: 'lola', country: 'de', type: 'human', priority: 6 }, { value: 'tiger', country: 'nl', type: 'animal', priority: 7 }, { value: 'koala', country: 'be', type: 'animal', priority: 8 }, { value: 'tiger', country: 'nl', type: 'animal', priority: 9 }],
    result = groupBy(list, 'value', 'country')
        .sort(({ type: a }, { type: b }) => a > b || -(a < b))
        .map((priority => (o, i, { [i - 1]: p }) => {
            if (p && p.type === o.type) ++priority;
            else priority = 1;
            return { ...o, priority };
        })());

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
0 голосов
/ 02 апреля 2020

Эльдар ответил хорошо. Просто нужно добавить проверку стран, прежде чем нажать одну и ту же страну дважды.

Я также заменил оператор распространения на фактический элемент списка, чтобы сохранить их структурный порядок.

const l2 = list.reduce((accumulator, currentValue) => {
    const {
        value,
        country,
        type,
        priority
    } = currentValue
    const existing = accumulator
        .find(item => item.value === currentValue.value)
    if (existing) {
        if (!(existing.countries.find(addedCountries => addedCountries === currentValue.country))) {
            existing.countries.push(currentValue.country)
        }
    } else {
        accumulator.push({ value,
            countries: [country],
            type,
            priority
        })
    }
    return accumulator
}, [])
0 голосов
/ 02 апреля 2020

Вам нужно проверить существующее значение, если его нет, добавить его, иначе pu sh новое значение в массиве страны.

var list = [
  {    value: 'fox',    country: 'nl',    type: 'animal',    priority: 1  },
  {    value: 'fox',    country: 'be',    type: 'animal',    priority: 2  },
  {    value: 'cat',    country: 'de',    type: 'animal',    priority: 3  },
  {    value: 'david',  country: 'nl',    type: 'human',     priority: 4  },
  {    value: 'marc',   country: 'be',    type: 'human',     priority: 5  },
  {    value: 'lola',   country: 'de',    type: 'human',     priority: 6  },
  {    value: 'tiger',  country: 'nl',    type: 'animal',    priority: 7  },
  {    value: 'koala',  country: 'be',    type: 'animal',    priority: 8  },
  {    value: 'tiger',  country: 'nl',    type: 'animal',    priority: 9  },
];

const l2 = list.reduce((accumulator, currentValue, index) => {
  const {
    country,
    ...value
  } = currentValue;
  const existing = accumulator
    .find(item => item.value === currentValue.value);
  if (existing) {
    const {
      countries
    } = existing;
    countries.push(country);
    existing.countries = Array.from(new Set(countries))
  } else {
    accumulator.push({ ...value,
      countries: [country]
    });
  }
  return accumulator;
}, [])

console.log(l2)
.as-console-wrapper {
  max-height: 100% !important;
  top: 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...