JS — разгруппировать массив по дате

#javascript #arrays

#javascript #массивы

Вопрос:

У меня есть такой массив:

 [
  {
    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
  }
]
  

Цель состоит в том, чтобы преобразовать этот массив в такой формат.

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

итого — общая сумма чисел за конкретную дату.

Вот что я пробовал до сих пор. Мой единственный вопрос заключается в том, как сгруппировать поля во вложенный массив? https://jsfiddle.net/7g3tLo0q /

 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
  }
]

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




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, 'res');  

Спасибо!

Комментарии:

1. пожалуйста, добавьте свой код к вопросу.

2. Добавлено @NinaScholz

Ответ №1:

Вы могли бы использовать вложенные циклы и сокращать группы и подгруппы и применять сортировку по date .

 const
    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 }],
    result = data
        .reduce((r, { group: name, subgroups }) => subgroups.reduce((days, { date, number: count }) => {
            let day = days.find(q => q.date === date);
            if (!day) days.push(day = { date, total: 0, issues: [] });
            day.issues.push({ name, count });
            day.total  = count;
            return days;
        }, r), [])
        .sort((a, b) => a.date.localeCompare(b.date));
 
console.log(result);  
 .as-console-wrapper { max-height: 100% !important; top: 0; }  

Ответ №2:

 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 fres = res.map((value, key)=>{
    value.issues = [];
    for (const key in value) {
            if(key=='total' || key=='issues' || key=='date'){
            continue;
        }
        value.issues.push({name:key, count:value.total})
    }
    return value;
  }
  );




console.log(fres);
  

Демонстрация:https://jsfiddle.net/yj9b12z3/34 /