0

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]
    }
  ]
2
  • How do you know, that the zero value should be placed in between the two exisiting values? Is it possible that there are objects which of ids have more than three values? Commented Mar 9, 2022 at 8:44
  • @Teemu Yes, it's quite possible, and I'm trying to figure out how to find out Commented Mar 9, 2022 at 8:51

1 Answer 1

1

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)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.