Skip to content
Advertisement

Set zero for missing data in array of objects

I have the following arrays of objects, for example:

const data = [
  {
    date: '01-01',
    products: [
      {
        id: 1,
        value: 6,
        label: 'Product 1'
      },
      {
        id: 2,
        value: 3,
        label: 'Product 2'
      }
    ]
  },
  {
    date: '02-01',
    products: [
      {
        id: 1,
        value: 4,
        label: 'Product 1'
      },
    ]
  },
  {
    date: '03-01',
    products: [
      {
        id: 1,
        value: 11,
        label: 'Product 1'
      },
      {
        id: 2,
        value: 15,
        label: 'Product 2'
      }
    ]
  }
]

Then I do the grouping and get the following result:

 const output = [
    {
      id: 1,
      name: 'Product 1',
      data: [6, 4, 11]
    },
    {
      id: 2,
      name: 'Product 2',
      data: [3, 15]
    }
  ]

The problem with the solution is that I cannot take into account the missing value (the object with the date “02-01” does not have an object with id: 2). I need to check that the object does not exist and substitute zero instead of the missing value. Maybe you know how to do it?

Solution code below:

const result = data.map(e => e.products).flat().reduce((acc, product) => {
    const index = acc.findIndex(item => item.id === product.id);

    if(index === -1) {
      acc.push({
        id: product.id,
        name: product.label,
        data: [product.value]
      })
      
      return acc;
    }

    const findIndex = acc[index].data.findIndex((innerNode) => innerNode.id === product.id);

    if (findIndex === -1) {
      console.log(product.value)
      acc[index].data.push(product.value);
      return acc;
    }

    return acc;
  }, []);

Expected result:

const output = [
    {
      id: 1,
      name: 'Product 1',
      data: [6, 4, 11]
    },
    {
      id: 2,
      name: 'Product 2',
      data: [3, 0, 15]
    }
  ]

Advertisement

Answer

You can do this in three passes:

  • first, you find all dates. When you first encounter a product, you will set all its values to 0 for each of those dates.
  • then, you iterate products and ensure that, for each date, they have a value – which will be zero by default.
  • finally, you format the output.

const data = [
  {
    date: '01-01',
    products: [
      {
        id: 1,
        value: 6,
        label: 'Product 1'
      },
      {
        id: 2,
        value: 3,
        label: 'Product 2'
      }
    ]
  },
  {
    date: '02-01',
    products: [
      {
        id: 1,
        value: 4,
        label: 'Product 1'
      },
    ]
  },
  {
    date: '03-01',
    products: [
      {
        id: 1,
        value: 11,
        label: 'Product 1'
      },
      {
        id: 2,
        value: 15,
        label: 'Product 2'
      }
    ]
  }
]

// goal is to fill this for each product
let dateToValues = data.map(d => [d.date, 0]);

// build map of product-id to values-for-each-date
let products = new Map();
data.forEach(d => d.products.forEach(p => {
  let values = products.get(p.id)?.data;  
  if (values === undefined) {
    values = new Map(dateToValues); // a copy
    products.set(p.id, {label: p.label, data: values});
  }
  values.set(d.date, p.value); 
}))

// generate output, skipping dates and only showing their values
let output = [];
products.forEach((v, id) => output.push({
  id: id, name: v.label, data: [... v.data.values()]}));
console.log(output)
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement