Как сгруппировать массив объектов по ключу и суммировать свойство вложенного объекта - PullRequest
0 голосов
/ 23 марта 2020

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

var products = [
{
    'id': '1',
    'currency': { id:1, name:'Dollar' },
    'price': '100'
}, {
    'id': '4',
    'currency': { 
        id:2, 
        name:'Euro',
        current_quotation: {
           date: '2020-03-02',
           quotation: 68
        } 
    },
    'price': '300'
}, {
    'id': '6',
    'currency': { id:1, name:'Dollar' },
    'price': '50'
}, {
    'id': '16',
    'currency': null,
    'price': '50'
}, {
    'id': '23',
    'currency': { id:2, name:'Euro' },
    'price': null
}
];

Я пытаюсь получить массив с уникальным объект за валюту с его ценовой суммой, предпочтительно с использованием loda sh или сценария ES6. В результате мне нужно:

var subtotals = [
    {currency:'Dollar', total: 150},
    {currency:'Euro', total: 300}
]

Я пробовал много образцов, но пока не повезло. Мой подход заключается в следующем, но он возвращает весь объект продукта в массиве, что очень далеко от ожидаемого результата

let subtotals = state.products.reduce((h, product) => Object.assign(h, { [product.currency?.name]:( h[product.currency?.name] || [] ).concat({currency: product.currency?.name, price: product.price}) }), {})

Результат

{
    "Euro":[
        {"currency":"Euro","price":"300"}
    ],
    "Dolar":[
        {"currency":"Dolar","price":"100"},
        {"currency":"Dolar","price":"50"}
    ]
}

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

Любая помощь будет оценена.

Ответы [ 3 ]

2 голосов
/ 23 марта 2020

Предполагая, что вы хотите подвести итоги и получить итоговую сумму в 300 евро:

Итерируйте по каждому currency.name и price, преобразовывая входные данные в объект, ключами которого являются названия валют и значения - это совокупная цена для названия валюты, найденного до сих пор. В конце сопоставьте записи объекта, чтобы получить массив объектов желаемого формата:

var products = [
  {
      'id': '1',
      'currency': { id:1, name:'Dollar' },
      'price': '100'
  }, {
      'id': '4',
      'currency': { id:2, name:'Euro' },
      'price': '300'
  }, {
      'id': '6',
      'currency': { id:1, name:'Dollar' },
      'price': '50'
  }
];

const pricesByName = {};
for (const { currency: { name }, price } of products) {
  pricesByName[name] = (pricesByName[name] || 0) + Number(price);
}
const output = Object.entries(pricesByName)
  .map(([currency, total]) => ({ currency, total }));
console.log(output);

Если валюта или цена нулевая, игнорируйте их, используя оператор if:

var products = [
{
    'id': '1',
    'currency': { id:1, name:'Dollar' },
    'price': '100'
}, {
    'id': '4',
    'currency': { id:2, name:'Euro' },
    'price': '300'
}, {
    'id': '6',
    'currency': { id:1, name:'Dollar' },
    'price': '50'
}, {
    'id': '16',
    'currency': null,
    'price': '50'
}, {
    'id': '23',
    'currency': { id:2, name:'Euro' },
    'price': null
}
];

const pricesByName = {};
for (const { currency, price } of products) {
  if (price === null || currency === null) continue;
  const { name } = currency;
  pricesByName[name] = (pricesByName[name] || 0) + Number(price);
}
const output = Object.entries(pricesByName)
  .map(([currency, total]) => ({ currency, total }));
console.log(output);
1 голос
/ 23 марта 2020

Используя loda sh, вы можете группировать по свойству name объекта валюты, используя _.groupBy(). А затем сопоставить результирующий объект с массивом объектов. Объект, на который вы отображаете, может использовать ключ в качестве валюты и итоговую сумму сгруппированного массива (используя _.sumBy()) в качестве общей суммы:

const products = [ { 'id': '1', 'currency': { id:1, name:'Dollar' }, 'price': '100' }, { 'id': '4', 'currency': { id:2, name:'Euro' }, 'price': '300' }, { 'id': '6', 'currency': { id:1, name:'Dollar' }, 'price': '50' }, { 'id': '16', 'currency': null, 'price': '50' }, { 'id': '23', 'currency': { id:2, name:'Euro' }, 'price': null } ];

const getSubTotals = p => _.flow(
  products => _.filter(products, o => _.has(o, p)),
  sm_prod => _.groupBy(sm_prod, p),
  gr => _.map(gr, (arr, currency) => ({currency, total: _.sumBy(arr, ({price}) => +price)}))
);

console.log(getSubTotals('currency.name')(products));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

РЕДАКТИРОВАТЬ Поскольку вы изменили свой вопрос. Вам нужно будет использовать альтернативный код, чтобы получить желаемый результат:

const products = [ { 'id': '1', 'currency': { id:1, name:'Dollar' }, 'price': '100' }, { 'id': '4', 'currency': { id:2, name:'Euro', current_quotation: { date: '2020-03-02', quotation: 68 } }, 'price': '300' }, { 'id': '6', 'currency': { id:1, name:'Dollar' }, 'price': '50' }, { 'id': '16', 'currency': null, 'price': '50' }, { 'id': '23', 'currency': { id:2, name:'Euro' }, 'price': null } ];

const getSubTotals = p => products => {
  const _gr = _(products).filter(o => _.has(o, p)).groupBy(p);
  const quote_map = _gr.mapValues((arr, k) => _.sumBy(arr, o => _.get(o, 'currency.current_quotation.quotation', 0)) || 1).value();
  const _totals = _gr.map((arr, currency) => ({currency, total: _.sumBy(arr, ({price}) => +price)}));
  return _totals.map(({currency, total, ...r}) => ({currency, total, quote_total: total*quote_map[currency]})).value();
}


console.log(getSubTotals('currency.name')(products));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
0 голосов
/ 23 марта 2020

Я написал это в консоли, и это должно работать для вашего случая:

var products = [
    {
        id: '1',
        currency: { id: 1, name: 'Dollar' },
        price: '100',
    },
    {
        id: '4',
        currency: { id: 2, name: 'Euro' },
        price: '300',
    },
    {
        id: '6',
        currency: { id: 1, name: 'Dollar' },
        price: '50',
    },
];

subtotals = {};

products.map(x => {
    if(x.currency !== null){
        subtotals[x.currency.name] === undefined
            ? (subtotals[x.currency.name] = parseInt(x.price))
            : (subtotals[x.currency.name] += parseInt(x.price));
    }
});
...