0

I need some help doing a dataset transformation.

I have this array of objects:

const CATEGORY = "category";
const DATE = "date";

const dataset = [
  { date: "2012", category: "pizza", valueA: 1, valueB: 1, valueC: 3 },
  { date: "2012", category: "fruit", valueA: 3, valueB: 3, valueC: 1 },
  { date: "2012", category: "pasta", valueA: 2, valueB: 2, valueC: 2 },
  { date: "2013", category: "pizza", valueA: 1, valueB: 2, valueC: 2 },
  { date: "2013", category: "fruit", valueA: 3, valueB: 2, valueC: 3 },
  { date: "2013", category: "pasta", valueA: 1, valueB: 3, valueC: 1 },
  { date: "2014", category: "pizza", valueA: 2, valueB: 1, valueC: 2 },
  { date: "2014", category: "fruit", valueA: 2, valueB: 2, valueC: 0 },
  { date: "2014", category: "pasta", valueA: 1, valueB: 3, valueC: 1 }
];

And I need:

const result = [
  { "date": "2012", "pizza": 1, "fruit": 3, "pasta": 2 },
  { "date": "2013", "pizza": 1, "fruit": 3, "pasta": 1 },
  { "date": "2014", "pizza": 2, "fruit": 2, "pasta": 1 }
]

So an array of objects, one for each date. The keys of this object should be the date and all the categories with their value of column kpi.

To do that I create this function:

function formatDataset(dataset, kpi) {
  const categories = uniqBy(dataset, CATEGORY).map((d) => d[CATEGORY]);
  const groupByDate = groupBy(dataset, DATE);
  const dates = Object.keys(groupByDate);
  const result = dates.map((date) => {
    return groupByDate[date].reduce((acc, datum, accI) => {
      acc = {
        ...acc,
        [datum[CATEGORY]]: datum[kpi] || 0,
        [DATE]: date
      };
      return acc;
    }, {});
  });
  return result;
}

It works, I don't know if there is a better way to do that but, anyway, it works.

The problem is that dataset may not have all the data, for example:

const dataset = [
  { date: "2012", category: "pizza", valueA: 1, valueB: 1, valueC: 3 },
  // { date: "2012", category: "fruit", valueA: 3, valueB: 3, valueC: 1 },
  { date: "2012", category: "pasta", valueA: 2, valueB: 2, valueC: 2 },
  { date: "2013", category: "pizza", valueA: 1, valueB: 2, valueC: 2 },
  { date: "2013", category: "fruit", valueA: 3, valueB: 2, valueC: 3 },
  { date: "2013", category: "pasta", valueA: 1, valueB: 3, valueC: 1 },
  { date: "2014", category: "pizza", valueA: 2, valueB: 1, valueC: 2 },
  { date: "2014", category: "fruit", valueA: 2, valueB: 2, valueC: 0 },
  { date: "2014", category: "pasta", valueA: 1, valueB: 3, valueC: 1 }
];

In that case the result is this:

[
    { "pizza": 1, "date": "2012", "pasta": 2 },
    { "pizza": 1, "date": "2013", "fruit": 3, "pasta": 1 },
    { "pizza": 2, "date": "2014", "fruit": 2, "pasta": 1 }
]

but it should be:

[
    { "pizza": 1, "date": "2012", "fruit": 0, "pasta": 2 },
    { "pizza": 1, "date": "2013", "fruit": 3, "pasta": 1 },
    { "pizza": 2, "date": "2014", "fruit": 2, "pasta": 1 }
]

How can I fix the function?

Here the code:

import * as _ from 'lodash';

const CATEGORY = "category";
const DATE = "date";

function flatize(dataset, kpi) {
  console.log("\n-- flatize --");

  const categories = uniqBy(dataset, CATEGORY).map((d) => d[CATEGORY]);
  console.log("categories: ", categories);

  const groupByDate = groupBy(dataset, DATE);
  console.log("groupByDate: ", groupByDate);

  const dates = Object.keys(groupByDate);
  console.log("dates: ", dates);

  const flatizedDataset = dates.map((date) => {
    return groupByDate[date].reduce((acc, datum, accI) => {
      console.log("- accI: ", accI);
      console.log("  datum: ", datum);
      console.log("  datum[CATEGORY]: ", datum[CATEGORY]);
      acc = {
        ...acc,
        [datum[CATEGORY]]: datum[kpi] || 0,
        [DATE]: date
      };
      return acc;
    }, {});
  });
  return flatizedDataset;
}

const dataset = [
  { date: "2012", category: "pizza", valueA: 1, valueB: 1, valueC: 3 },
  // { date: "2012", category: "fruit", valueA: 3, valueB: 3, valueC: 1 },
  { date: "2012", category: "pasta", valueA: 2, valueB: 2, valueC: 2 },
  { date: "2013", category: "pizza", valueA: 1, valueB: 2, valueC: 2 },
  { date: "2013", category: "fruit", valueA: 3, valueB: 2, valueC: 3 },
  { date: "2013", category: "pasta", valueA: 1, valueB: 3, valueC: 1 },
  { date: "2014", category: "pizza", valueA: 2, valueB: 1, valueC: 2 },
  { date: "2014", category: "fruit", valueA: 2, valueB: 2, valueC: 0 },
  { date: "2014", category: "pasta", valueA: 1, valueB: 3, valueC: 1 }
];

const flatDataset = flatize(dataset, "valueA");

console.log("dataset:", dataset);
console.log("flatDataset:", flatDataset);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

2 Answers 2

1

Here is a non lodash solution. What to take from here is I'm creating an initializer which will look like {pizza: 0, fruit: 0,....} depending on the unique categories and then I'm setting a copy of it inside the reduce for every new group by date

const dataset = [  { date: "2012", category: "pizza", valueA: 1, valueB: 1, valueC: 3 },  { date: "2012", category: "fruit", valueA: 3, valueB: 3, valueC: 1 },  { date: "2012", category: "pasta", valueA: 2, valueB: 2, valueC: 2 },  { date: "2013", category: "pizza", valueA: 1, valueB: 2, valueC: 2 },  { date: "2013", category: "fruit", valueA: 3, valueB: 2, valueC: 3 }, { date: "2013", category: "pasta", valueA: 1, valueB: 3, valueC: 1 },  { date: "2014", category: "pizza", valueA: 2, valueB: 1, valueC: 2 },  { date: "2014", category: "fruit", valueA: 2, valueB: 2, valueC: 0 },  { date: "2014", category: "pasta", valueA: 1, valueB: 3, valueC: 1 }];


function flatize(dataset, kpi) {
  const uniqCategories = [...new Set(dataset.map(({category})=>category))]
  const initializer = Object.fromEntries(uniqCategories.map((c) => [c,0]))

  const groupedByDate = dataset.reduce((acc,{date,category,[kpi]:value})=>{
    acc[date] = acc[date]||{date,...initializer}
    acc[date][category] = value
    return acc
   },{}) 
  return Object.values(groupedByDate)
}

console.log(flatize(dataset,'valueC'))

same change can be added to your implementation as well

const CATEGORY = "category";
const DATE = "date";

function flatize(dataset, kpi) {
  const categories = _.uniqBy(dataset, CATEGORY).map((d) => d[CATEGORY]);
  const groupByDate = _.groupBy(dataset, DATE);
  const initializer = Object.fromEntries(categories.map((c) => [c,0]))
  const dates = Object.keys(groupByDate);

  const flatizedDataset = dates.map((date) => {
    return groupByDate[date].reduce((acc, datum, accI) => {
      acc = {
        ...initializer,
        ...acc,
        [datum[CATEGORY]]: datum[kpi] || 0,
        [DATE]: date
      };
      return acc;
    }, {});
  });
  return flatizedDataset;
}

const dataset = [
  { date: "2012", category: "pizza", valueA: 1, valueB: 1, valueC: 3 },
 // { date: "2012", category: "fruit", valueA: 3, valueB: 3, valueC: 1 },
  { date: "2012", category: "pasta", valueA: 2, valueB: 2, valueC: 2 },
  { date: "2013", category: "pizza", valueA: 1, valueB: 2, valueC: 2 },
  { date: "2013", category: "fruit", valueA: 3, valueB: 2, valueC: 3 },
  { date: "2013", category: "pasta", valueA: 1, valueB: 3, valueC: 1 },
  { date: "2014", category: "pizza", valueA: 2, valueB: 1, valueC: 2 },
  { date: "2014", category: "fruit", valueA: 2, valueB: 2, valueC: 0 },
  { date: "2014", category: "pasta", valueA: 1, valueB: 3, valueC: 1 }
];

const flatDataset = flatize(dataset, "valueA");

console.log(flatDataset);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

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

Comments

0

Try this

const normalize = (data, key) => {
    let resultObj = {};

    data.forEach(item => {
        resultObj[item.date] = {
            pizza: 0,
            fruit: 0,
            pasta: 0,
            ...resultObj[item.date] || {},
            date: item.date,
            [item.category]: item[key]
        };
    });

    return Object.values(resultObj);
}

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.