Home > Software design >  How to restructure data using reduce?
How to restructure data using reduce?

Time:08-31

I am getting data from API structured like this:

interface ProductModel {
    prod_id: string,
    brand: string,
    ...
}

interface OrderModel {
    order_id: string,
    prod_id: string,
    ...
}

const data = {
    products: ProductModel[],
    orders: OrderModel[]
}

What I want is to restructure the data to group the orders of a product and the product info in one object:

const expectedStructure = {
    prod_id: string,
    brand: string,
    ...,
    orders: OrderModel[]
}

I suppose that with a reduce it could be done easily, but I don't quite understand how it works. Could someone help me with this example?

CodePudding user response:

You could just use the spread operator which "flattens" the object's properties.

const expectedStructure = { ...products, orders }

CodePudding user response:

const data = {
    products: ProductModel[],
    orders: OrderModel[]
}

const {products, orders} = data;

const expectedStructure = {
   ...products,
   orders,
}

checkout: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

checkout: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

CodePudding user response:

Reduce can be used but you dont really need it, simple .map with .filter and ... spread operator:

const products = [
  { prod_id: "1", brand: "brand1" },
  { prod_id: "2", brand: "brand1" },
  { prod_id: "3", brand: "brand2" },
  { prod_id: "4", brand: "brand2" },
  { prod_id: "5", brand: "brand3" }
];
const orders = [
  { order_id: "1", prod_id: "1" },
  { order_id: "2", prod_id: "2" },
  { order_id: "3", prod_id: "3" },
  { order_id: "4", prod_id: "3" },
  { order_id: "5", prod_id: "4" }
];

const data = {
  products: products,
  orders: orders
};

function groupData(data) {
  if (!data) return data;
  return data.products.map((p) => ({
    ...p,
    orders: data.orders.filter((x) => x.prod_id === p.prod_id)
  }));
}

console.log(groupData(data));

Adding a little optimization asked in comments using Map class. With that you will only need 1 loop over initial Orders array to build the Map object and then you will have a constant time of element retrieval:

const products = [
  { prod_id: "1", brand: "brand1" },
  { prod_id: "2", brand: "brand1" },
  { prod_id: "3", brand: "brand2" },
  { prod_id: "4", brand: "brand2" },
  { prod_id: "5", brand: "brand3" }
];
const orders = [
  { order_id: "1", prod_id: "1" },
  { order_id: "2", prod_id: "2" },
  { order_id: "3", prod_id: "3" },
  { order_id: "4", prod_id: "3" },
  { order_id: "5", prod_id: "4" }
];

const data = {
  products: products,
  orders: orders
};

function buildMap(data) {
  const res = new Map();
  data.orders.forEach((order) => {
    if (res.has(order.prod_id)) {
      res.get(order.prod_id).push(order);
    } else {
      res.set(order.prod_id, [order]);
    }
  });
  return res;
}

function groupData(data) {
  if (!data) return data;
  const ordersMap = buildMap(data);
  return data.products.map((p) => ({
    ...p,
    orders: ordersMap.get(p.prod_id) || []
  }));
}

console.log(groupData(data));

  • Related