0

I have such an array structure:

[
  {
    group: "perf",
    subgroups: [
      {
        date: "2020-08-20",
        number: 2
      },
      {
        date: "2020-08-21",
        number: 3
      }
    ],
    number: 5
  },
  {
    group: "mobile",
    subgroups: [
      {
        date: "2020-08-20",
        number: 4
      },
      {
        date: "2020-08-21",
        number: 6
      }
    ],
    number: 10
  },
  {
    group: "games",
    subgroups: [
      {
        date: "2020-08-20",
        number: 7
      },
      {
        date: "2020-08-21",
        number: 8
      },
        {
        date: "2020-08-22",
        number: 1
      }
    ],
    number: 16
  },
  {
    group: "levels",
    subgroups: [
      {
        date: "2020-08-09",
        number: 4
      },
      {
        date: "2020-08-20",
        number: 9
      },
      {
        date: "2020-08-21",
        number: 11
      }
    ],
    number: 24
  }
]

I need to create a mapper over this array to receive such output:

total - the overall sum of numbers for the specific date.

[
    {
      date: "2020-08-09",
      total: 4,
      levels: 4
    },
    {
      date: "2020-08-20",
      total: 22,
      perf: 2,
      mobile: 4,
      games: 7,
      levels: 9,
    },
    {
      date: "2020-08-21",
      total: 28,
      perf: 3,
      mobile: 6,
      games: 8,
      levels: 11,
    },
    {
      date: "2020-08-22",
      total: 1,
      games: 1
    }
]

How can this be achieved? I was trying, using reduce but cannot figure out, how to group it by dates.

Here's what I've tried so far: https://jsfiddle.net/wqhj62od/

Or maybe it can be done easily using lodash?

Thank you!

2 Answers 2

1

You could do this with plain JS, require some manipulation here

  • group total value of each type by date
  • map through the group and calculate the total of all values
const dateValueLookup = arr.reduce((acc, el) => {
  el.subgroups.forEach((subgroup) => {
    if (!acc[subgroup.date]) {
      acc[subgroup.date] = {}
    }
    if (!acc[subgroup.date][el.group]) {
      acc[subgroup.date][el.group] = 0
    }
    acc[subgroup.date][el.group] += subgroup.number
  })
  return acc
}, {})

const res = Object.entries(dateValueLookup)
  .sort(([keyA], [keyB]) => keyA.localeCompare(keyB))
  .map(([date, values]) => ({
    date,
    total: Object.values(values).reduce((sum, value) => sum + value, 0),
    ...values,
  }))

const arr = [
  {
    group: "perf",
    subgroups: [
      {
        date: "2020-08-20",
        number: 2,
      },
      {
        date: "2020-08-21",
        number: 3,
      },
    ],
    number: 5,
  },
  {
    group: "mobile",
    subgroups: [
      {
        date: "2020-08-20",
        number: 4,
      },
      {
        date: "2020-08-21",
        number: 6,
      },
    ],
    number: 10,
  },
  {
    group: "games",
    subgroups: [
      {
        date: "2020-08-20",
        number: 7,
      },
      {
        date: "2020-08-21",
        number: 8,
      },
      {
        date: "2020-08-22",
        number: 1,
      },
    ],
    number: 16,
  },
  {
    group: "levels",
    subgroups: [
      {
        date: "2020-08-09",
        number: 4,
      },
      {
        date: "2020-08-20",
        number: 9,
      },
      {
        date: "2020-08-21",
        number: 11,
      },
    ],
    number: 24,
  },
]

const dateValueLookup = arr.reduce((acc, el) => {
  el.subgroups.forEach((subgroup) => {
    if (!acc[subgroup.date]) {
      acc[subgroup.date] = {}
    }
    if (!acc[subgroup.date][el.group]) {
      acc[subgroup.date][el.group] = 0
    }
    acc[subgroup.date][el.group] += subgroup.number
  })
  return acc
}, {})

const res = Object.entries(dateValueLookup)
  .sort(([keyA], [keyB]) => keyA.localeCompare(keyB))
  .map(([date, values]) => ({
    date,
    total: Object.values(values).reduce((sum, value) => sum + value, 0),
    ...values,
  }))

console.log(res)

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

Comments

1

You could create a Map keyed by date, with the final objects as values. Then iterate the data and update those objects. Finally extract the values from the Map and sort them:

function ungroup(data) {
    let map = new Map(data.flatMap(({subgroups}) => 
        subgroups.map(({date}) => [date, { date, total: 0 }])
    ));
    for (let {group, subgroups} of data) {
        for (let {date, number} of subgroups) {
            let obj = map.get(date);
            obj.total += obj[group] = number;
        }
    }
    return Array.from(map.values()).sort((a, b) => a.date.localeCompare(b.date));
}

let data = [{group: "perf",subgroups: [{date: "2020-08-20",number: 2},{date: "2020-08-21",number: 3}],number: 5},{group: "mobile",subgroups: [{date: "2020-08-20",number: 4},{date: "2020-08-21",number: 6}],number: 10},{group: "games",subgroups: [{date: "2020-08-20",number: 7},{date: "2020-08-21",number: 8},{date: "2020-08-22",number: 1}],number: 16},{group: "levels",subgroups: [{date: "2020-08-09",number: 4},{date: "2020-08-20",number: 9},{date: "2020-08-21",number: 11}],number: 24}];
let result = ungroup(data);
console.log(result);

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.