Добавить общее количество строк для 2 из 3 элементов в массиве объектов - PullRequest
0 голосов
/ 25 мая 2018

Мне нужна помощь с этим матричным алгоритмом:

Ввод:

const reqObj = [
    ['Anna', 'Class', 'Cycling', '10'],
    ['Anna', 'Class', 'Boxing', '25'],
    ['Anna', 'Class', 'Climbing', '20'],
    ['Anna', 'Misc', 'Towel', '5'],
    ['Anna', 'Drink', 'Coffee', '3'],
    ['Anna', 'Drink', 'Tea', '4'],
    ['Beatrice', 'Drink', 'Tea', '4'],
    ['Beatrice', 'Class', 'Kickboxing', '25'],
    ['Beatrice', 'Misc', 'Lock', '20'],
    ['Beatrice', 'Misc', 'Towel', '5']
]

Ожидаемый результат:

const resObj = [
    ['Anna', 'Class', 'Cycling', '10'],
    ['Anna', 'Class', 'Boxing', '25'],
    ['Anna', 'Class', 'Climbing', '20'],
    ['Anna', 'Misc', 'Towel', '5'],
    ['Anna', 'Drink', 'Coffee', '3'],
    ['Anna', 'Drink', 'Tea', '4'],
    ['Anna', 'Class', 'Total classes', '55'],
    ['Anna', 'Drink', 'Total drinks', '7'],
    ['Beatrice', 'Drink', 'Tea', '4'],
    ['Beatrice', 'Class', 'Kickboxing', '25'],
    ['Beatrice', 'Misc', 'Lock', '20'],
    ['Beatrice', 'Misc', 'Towel', '5'],
    ['Beatrice', 'Class', 'Total classes', '25'],
    ['Beatrice', 'Drink', 'Total drinks', '4']
]

В словах:

  • Цикл по массиву объектов содержит данные нескольких человек.
  • Если один и тот же человек, тот же сервис (не Misc), получает сумму из стоимость услуги , замените имя службы на полное имя и добавьте в конец строк данные этого человека.

Вот мой код:

const totalRow = arr => {
    let result = [].concat(...arr.reduce((acc, [person, service, type, amount]) => {
            let data = acc.get(person) || [[person, service, type, '0']]
            if (service === 'Class') data.push([person, service, 'Total classes', amount])
            else if (service === 'Drink') data.push([person, service, 'Total drinks', amount])
            data[0][3] = (+data[0][3] + +amount).toString()
            return acc.set(person, data)
        }, new Map)
        .values()
    )

    return result
}

const totalRowResult = totalRow(reqObj)

console.log(totalRowResult)

Обновление

Вывод с отрицательной суммой:

const resObj = [
    ['Anna', 'Class', 'Cycling', '10'],
    ['Anna', 'Class', 'Boxing', '25'],
    ['Anna', 'Class', 'Climbing', '20'],
    ['Anna', 'Misc', 'Towel', '5'],
    ['Anna', 'Drink', 'Coffee', '3'],
    ['Anna', 'Drink', 'Tea', '4'],
    ['Anna', 'Class', 'Total classes', '-55'],
    ['Anna', 'Drink', 'Total drinks', '-7'],
    ['Beatrice', 'Drink', 'Tea', '4'],
    ['Beatrice', 'Class', 'Kickboxing', '25'],
    ['Beatrice', 'Misc', 'Lock', '20'],
    ['Beatrice', 'Misc', 'Towel', '5'],
    ['Beatrice', 'Class', 'Total classes', '-25'],
    ['Beatrice', 'Drink', 'Total drinks', '-4']
]

Ответы [ 2 ]

0 голосов
/ 25 мая 2018

Другое возможное решение:

// Your input data
const input = [
  ['Anna', 'Class', 'Cycling', '10'],
  ['Anna', 'Class', 'Boxing', '25'],
  ['Anna', 'Class', 'Climbing', '20'],
  ['Anna', 'Misc', 'Towel', '5'],
  ['Anna', 'Drink', 'Coffee', '3'],
  ['Anna', 'Drink', 'Tea', '4'],
  ['Beatrice', 'Drink', 'Tea', '4'],
  ['Beatrice', 'Class', 'Kickboxing', '25'],
  ['Beatrice', 'Misc', 'Lock', '20'],
  ['Beatrice', 'Misc', 'Towel', '5']
];

// Returns all items which contain the given name
const getAllPersonsItems = name => input.filter(currentItem => currentItem[0] === name);

// Returns all items which contain the given name and item
const getPersonsItems = (name, item) => getAllPersonsItems(name).filter(currentItem => currentItem[1] === item);

// Returns total of given items (template string is used to return the total as a string - not number)
const getItemsTotal = items => `${items.reduce((acc, cur) => parseInt(cur[3], 10) + acc, 0)}`;

// Returns all existing names
const names = input.reduce((acc, cur) => acc.indexOf(cur[0]) > -1 ? acc : [cur[0], ...acc], []);

// Loops through each name and creates items totals
const totals = names.reduce((acc, name) => acc
  .concat(getAllPersonsItems(name))
  .concat([
    [name, 'class', 'Total classes', getItemsTotal(getPersonsItems(name, 'Class'))],
    [name, 'drink', 'Total drinks', getItemsTotal(getPersonsItems(name, 'Drink'))],
  ]), []);

// Logs your desired output
console.log(totals);
0 голосов
/ 25 мая 2018

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

var array = [['Anna', 'Class', 'Cycling', '10'], ['Anna', 'Class', 'Boxing', '25'], ['Anna', 'Class', 'Climbing', '20'], ['Anna', 'Misc', 'Towel', '5'], ['Anna', 'Drink', 'Coffee', '3'], ['Anna', 'Drink', 'Tea', '4'], ['Beatrice', 'Drink', 'Tea', '4'], ['Beatrice', 'Class', 'Kickboxing', '25'], ['Beatrice', 'Misc', 'Lock', '20'], ['Beatrice', 'Misc', 'Towel', '5']],
    plurals = { class: 'classes' },
    result = [].concat(...Array.from(array
        .reduce((m, a) => {
            var [person, service, type, cost] = a,
                data = m.get(person) || { _: [], i: 0 };

            data._.splice(data.i++, 0, a);
            if (service !== 'Misc') {
                if (!data[service]) {
                    data[service] = [person, service, 'Total ' + (plurals[service.toLowerCase()] || service.toLowerCase() + 's'), '0'];
                    data._.push(data[service]);
                }
                data[service][3] = (+data[service][3] + +cost).toString();
            }
            return m.set(person, data);
        }, new Map)
        .values(), ({ _ }) => _)
    );

document.write('' + JSON.stringify(result.map(a => a.join(' ')), 0, 4) + '
');console.log (result.map (a => a.join ('')));console.log (результат);
.as-console-wrapper { max-height: 100% !important; top: 0; }
...