0

What I've got is array of objects

 const incomeRows = [
  {
    group: "Deck 1",
    categories: [
      { category: "Deck Supplies", reportvalue: 100, transdate: "2020-11" },
      { category: "Deck Supplies", reportvalue: 200, transdate: "2020-11" },
      { category: "Deck Contractors", reportvalue: 300, transdate: "2020-11" },
      { category: "Deck Contractors", reportvalue: 400, transdate: "2020-12" },
      { category: "Deck Contractors", reportvalue: 500, transdate: "2020-12" }
    ]
  },
  {
    group: "Deck 2",
    categories: [
      { category: "Deck Supplies", reportvalue: 10, transdate: "2020-11" },
      { category: "Deck Supplies", reportvalue: 20, transdate: "2020-11" },
      { category: "Deck Contractors", reportvalue: 30, transdate: "2020-11" },
      { category: "Deck Contractors", reportvalue: 40, transdate: "2020-12" },
      { category: "Deck Contractors", reportvalue: 50, transdate: "2020-12" }
    ]
  }
];

What I need to create is:

const finalOutput = [
  {
    group: "Deck 1",
    categories: [
      {
        category: "Deck Supplies",
        "2020-11": 300
      },
      {
        category: "Deck Contractors",
        "2020-11": 300,
        "2020-12": 900
      }
    ],
    groupMonthlyIncomes: {
      "2020-11": 600,
      "2020-12": 900
    }
  },
  {
    group: "Deck 2",
    categories: [
      {
        category: "Deck Supplies",
        "2020-11": 30
      },
      {
        category: "Deck Contractors",
        "2020-11": 30,
        "2020-12": 90
      }
    ],
    groupMonthlyIncomes: {
      "2020-11": 60,
      "2020-12": 90
    }
  }
];

So the category is unique and it has total values for each month like "2020-11": 300 and each group has its total monthly values like

groupMonthlyIncomes: {
 "2020-11": 60,
 "2020-12": 90
}

What I've done so far is:

let formatedRows = incomeRows.map(el => (
  {
    group: el.group,
    categories: []
  }
));

let formatedCategories = incomeRows.map(el => (
  el.categories.map(cat => {
    return {
      category: cat.category,
      [cat.transdate.toString()]: cat.reportvalue
    }
  })
));

Can anybody let me know what should be the next step or point me into any other solution if there is a better way to do it?

3 Answers 3

1

Try this one:

  incomeRows.map((row) => {
  const reportValues = row.categories.reduce((result, next) => {
    const catKey = next.category;
    const total = row.categories.
      filter((_cat) => _cat.category === next.category && _cat.transdate === next.transdate)
      .reduce((accum, _next) => accum + _next.reportvalue, 0);
    result[catKey] = result[catKey] ? {...result[catKey], [next.transdate]: total} : {[next.transdate]: total};
    return result;
  }, {});
  return {
    group: row.group,
    categories: Object.keys(reportValues).map((_key) => {
      return {
        category: _key,
        ...reportValues[_key],
      }
    }),
    groupMonthlyIncomes: row.categories.reduce((result, next) => {
      const key = next.transdate;
      result[key] = result[key] ? result[key] + next.reportvalue : next.reportvalue;
      return result;
    }, {}),
  }
});
Sign up to request clarification or add additional context in comments.

1 Comment

You are a star! This is working perfectly and it's ease enough for me to understand for the future. Thank you very much Sir! :)
1

try this:

incomeRows.map((row) => {
  return {
    group: row.group,
    categories: row.categories.map((cat) => {
      return {
        category: cat.category,
        [cat.transdate]: cat.reportvalue,
      }
    }),
    groupMonthlyIncomes: row.categories.reduce((result, next) => {
      const key = next.transdate;
      result[key] = result[key] ? result[key] + next.reportvalue : next.reportvalue;
      return result;
    }, {}),
  }
});

2 Comments

Hi Jafar, Thanks for your beautiful and easy to understand solution. We are almost there, however the final output is not what I'm trying to get. In your solution we have categories duplicated instead of being unique with total values grouped for each month. What I've done next is trying using another reduce inside but can't get it working :(
Okay, will add an other answer
1

const reorganization = () => {

    // declares an array of property names
    const attrs = ['category', 'transdate', 'reportvalue', 'categories', 'groupMonthlyIncomes'];

    return incomeRows.map(row => {

        // do something for categories
        const categorieMap = new Map([...new Map(row.categories.map(item => [item[attrs[0]], new Map()]))]);
        const categories = [...categorieMap.keys()];
        for (let i = 0; i < categories.length; i++) {
            const _map = categorieMap.get(categories[i]);
            for (let j = 0; j < row.categories.length; j++) {

                if (row.categories[j][attrs[0]] == categories[i]) {
                    const _mapKey = row.categories[j][attrs[1]];
                    const _mapVal = row.categories[j][attrs[2]];
                    _map.set(_mapKey, _map.has(_mapKey) ? _map.get(_mapKey) + _mapVal : _mapVal);
                }
            }
            _map.set(attrs[0], categories[i]);
            categories[i] = Object.fromEntries([..._map].map(
                m => m.flat()).map(a => ({
                [a[0]]: a[1]
            })).flatMap(Object.entries));
        }
        row[attrs[3]] = categories;

        // do something for groupMonthlyIncomes
        let groupMonthlyIncomes = new Map();
        for (let i = 0; i < categories.length; i++) {
            const categorie = categories[i];
            delete categorie[attrs[0]];
            for (const [key, value] of Object.entries(categories[i])) {
                groupMonthlyIncomes.set(key, groupMonthlyIncomes.has(key) ? groupMonthlyIncomes.get(key) + value : value);
            }
        }
        row[attrs[4]] = Object.fromEntries([...groupMonthlyIncomes].map(
            m => m.flat()).map(a => ({
            [a[0]]: a[1]
        })).flatMap(Object.entries));

        return row;
    });
}

const incomeRows = [{
        group: "Deck 1",
        categories: [{
                category: "Deck Supplies",
                reportvalue: 100,
                transdate: "2020-11"
            },
            {
                category: "Deck Supplies",
                reportvalue: 200,
                transdate: "2020-11"
            },
            {
                category: "Deck Contractors",
                reportvalue: 300,
                transdate: "2020-11"
            },
            {
                category: "Deck Contractors",
                reportvalue: 400,
                transdate: "2020-12"
            },
            {
                category: "Deck Contractors",
                reportvalue: 500,
                transdate: "2020-12"
            }
        ]
    },
    {
        group: "Deck 2",
        categories: [{
                category: "Deck Supplies",
                reportvalue: 10,
                transdate: "2020-11"
            },
            {
                category: "Deck Supplies",
                reportvalue: 20,
                transdate: "2020-11"
            },
            {
                category: "Deck Contractors",
                reportvalue: 30,
                transdate: "2020-11"
            },
            {
                category: "Deck Contractors",
                reportvalue: 40,
                transdate: "2020-12"
            },
            {
                category: "Deck Contractors",
                reportvalue: 50,
                transdate: "2020-12"
            }
        ]
    }
];

console.log(reorganization());

2 Comments

The final output is correct but whole solution is too difficult to understand for me. Thanks for your help anyway
@dariusz The pleasure is all mine. Mainly use Map and Array.prototype.map() to traverse and compare data, I should write more detailed logic annotations, I am sorry about that

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.