Sean
Sean

Reputation: 721

Summarise Collection Functionally

Can someone suggest a way to do this functionally? Maybe with reduce()? if name, weight and grind are the same then add the quantity in a summarised collection. Maybe lodash?

let bigOrder = [
  { name: "House Blend", quantity: 1, weight: "250g", grind: "whole-beans" },
  { name: "House Blend", quantity: 3, weight: "250g", grind: "filter" },
  { name: "Decaf", quantity: 1, weight: "250g", grind: "whole-beans" },
  { name: "Colombia", quantity: 4, weight: "250g", grind: "home-espresso" },
  { name: "Decaf", quantity: 1, weight: "250g", grind: "whole-beans" },
  { name: "House Blend", quantity: 2, weight: "250g", grind: "filter" },
  { name: "Colombia", quantity: 1, weight: "250g", grind: "filter" },
  { name: "Decaf", quantity: 1, weight: "250g", grind: "plunger" },
  { name: "Colombia", quantity: 3, weight: "1kg", grind: "whole-beans" },
  { name: "Colombia", quantity: 1, weight: "250g", grind: "whole-beans" },
  { name: "Decaf", quantity: 1, weight: "250g", grind: "plunger" },
  { name: "House Blend", quantity: 5, weight: "1kg", grind: "filter" },
  { name: "House Blend", quantity: 5, weight: "1kg", grind: "filter" },
  { name: "House Blend", quantity: 4, weight: "250g", grind: "filter" }
];

const summariseOrder = () => {
  let summary = [];

  bigOrder.forEach(line => {
    function comparator(a, b) {
      return a.name === b.name && a.weight === b.weight && a.grind === b.grind;
    }

    let index = summary.findIndex(e => comparator(e, line));
    if (index > 0) {
      summary[index].quantity += line.quantity;
    } else {
      summary.push(line);
    }
  });

  return summary;
};

console.log(summariseOrder());

Upvotes: 0

Views: 19

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 371118

You can use reduce by creating a key from the name, weight, and grind - if said key already exists in the accumulator object, add to the .quantity in that already-existing object, and at the end, get that object's values:

let bigOrder = [
  { name: "House Blend", quantity: 1, weight: "250g", grind: "whole-beans" },
  { name: "House Blend", quantity: 3, weight: "250g", grind: "filter" },
  { name: "Decaf", quantity: 1, weight: "250g", grind: "whole-beans" },
  { name: "Colombia", quantity: 4, weight: "250g", grind: "home-espresso" },
  { name: "Decaf", quantity: 1, weight: "250g", grind: "whole-beans" },
  { name: "House Blend", quantity: 2, weight: "250g", grind: "filter" },
  { name: "Colombia", quantity: 1, weight: "250g", grind: "filter" },
  { name: "Decaf", quantity: 1, weight: "250g", grind: "plunger" },
  { name: "Colombia", quantity: 3, weight: "1kg", grind: "whole-beans" },
  { name: "Colombia", quantity: 1, weight: "250g", grind: "whole-beans" },
  { name: "Decaf", quantity: 1, weight: "250g", grind: "plunger" },
  { name: "House Blend", quantity: 5, weight: "1kg", grind: "filter" },
  { name: "House Blend", quantity: 5, weight: "1kg", grind: "filter" },
  { name: "House Blend", quantity: 4, weight: "250g", grind: "filter" }
];

const summariseOrder = arr => Object.values(arr.reduce(
  (a, obj) => {
    const key = `${obj.name}_${obj.weight}_${obj.grind}`;
    if (!a[key]) a[key] = obj;
    else a[key].quantity += obj.quantity;
    return a;
  }, {}
));
console.log(summariseOrder(bigOrder));

Upvotes: 2

Related Questions