2

I have this array of objects:

[
  {
    "date": "08/08/2022",
    "name": "Swordsman",
    "items": [
      {
        "item_id": 1,
        "item": {
          "item_name": "Item 1",
        },
        "count": 1
      }
    ]
  },
  {
    "date": "08/08/2022",
    "name": "Swordsman",
    "items": [
      {
        "item_id": 1,
        "item": {
          "item_name": "Item 1",
        },
        "count": 2
      },
      {
        "item_id": 2,
        "item": {
          "item_name": "Item 2",
        },
        "count": 1
      }
    ]
  }
]

What I wanted to achieve is to group by date, name and the number of items. The desired result would be:

[
  {
    "date": "08/08/2022",
    "name": "Swordsman",
    "items": [
      {
        "item_id": 1,
        "name": "Item 1",
        "count": 3
      },
      {
        "item_id": 2,
        "name": "Item 2",
        "count": 1
      }
    ]
  }
]

If it has the same date but different name like:

[
  {
    "date": "08/08/2022",
    "name": "Swordsman",
    "items": [
      {
        "item_id": 1,
        "item": {
          "item_name": "Item 1",
        },
        "count": 1
      }
    ]
  },
  {
    "date": "08/08/2022",
    "name": "Swordsman",
    "items": [
      {
        "item_id": 1,
        "item": {
          "item_name": "Item 1",
        },
        "count": 2
      },
      {
        "item_id": 2,
        "item": {
          "item_name": "Item 2",
        },
        "count": 1
      }
    ]
  },
  {
    "date": "08/08/2022",
    "name": "Archer",
    "items": [
      {
        "item_id": 1,
        "item": {
          "item_name": "Item 1",
        },
        "count": 2
      },
      {
        "item_id": 2,
        "item": {
          "item_name": "Item 2",
        },
        "count": 1
      }
    ]
  }
]

The desired result would be:

[
  {
    "date": "08/08/2022",
    "name": "Swordsman",
    "items": [
      {
        "item_id": 1,
        "name": "Item 1",
        "count": 3
      },
      {
        "item_id": 2,
        "name": "Item 2",
        "count": 1
      }
    ]
  },
  {
    "date": "08/08/2022",
    "name": "Archer",
    "items": [
      {
        "item_id": 1,
        "name": "Item 1",
        "count": 2
      },
      {
        "item_id": 2,
        "name": "Item 2",
        "count": 1
      }
    ]
  }
]

I've tried using lodash and array reduce method but still unable to get the desired result:

const groups = data.reduce((groups, data) => {
  const date = data.date;
  if (!groups[date]) {
    groups[date] = [];
  }
  
  groups[date].push(data);
  return groups;
}, {});

const groupArrays = Object.keys(groups).map((date) => {
  return {
    date,
    items: groups[date]
  };
});

How to achieve this one? Need your inputs. Thanks!

2 Answers 2

1

You can achieve this as:

const arr = [
    {
        date: '08/08/2022',
        name: 'Swordsman',
        items: [
            {
                item_id: 1,
                item: {
                    item_name: 'Item 1',
                },
                count: 1,
            },
        ],
    },
    {
        date: '08/08/2022',
        name: 'Swordsman',
        items: [
            {
                item_id: 1,
                item: {
                    item_name: 'Item 1',
                },
                count: 2,
            },
            {
                item_id: 2,
                item: {
                    item_name: 'Item 2',
                },
                count: 1,
            },
        ],
    },
    {
        date: '08/08/2022',
        name: 'Archer',
        items: [
            {
                item_id: 1,
                item: {
                    item_name: 'Item 1',
                },
                count: 2,
            },
            {
                item_id: 2,
                item: {
                    item_name: 'Item 2',
                },
                count: 1,
            },
        ],
    },
];

function addItemsToNewArrFromOld(oldItems, newItemsToAdd) {
    newItemsToAdd.forEach((o) => {
        const { item_id, count, item: { item_name: item }} = o;
        const itemInOldItems = oldItems.find((obj) => obj.item_id === o.item_id);
        if (itemInOldItems) itemInOldItems.count += o.count;
        else oldItems.push({ item_id, count, item });
    });
}

const map = new Map();
arr.forEach(({ date, name, items }) => {
    const key = `${date}-${name}`;

    if (map.has(key)) {
        const objForKeyFound = map.get(key);
        addItemsToNewArrFromOld(objForKeyFound.items, items);
    } else {
        map.set(key, {
            date, name, items: items.map(({ item_id, item, count }) => ({ item_id, count, item: item.item_name })),
        });
    }
});

const result = [...map.values()];
console.log(result);

0
1
  • Using Array#reduce, iterate over the list while updating a Map where the key is <date>-<name> and the value is the grouped object (having all items of this key).
  • Using Array#map, iterate over the above grouped objects. For each object, we need to group its items by item_id while updating the count.

const groupByDateAndName = arr => [...
  arr.reduce((map, { date, name, items = [] }) => {
    const key = `${date}-${name}`;
    const { items: prevItems = [] } = map.get(key) ?? {};
    map.set(
      key, 
      { 
        date, 
        name, 
        items: [
          ...prevItems,
          ...items.map(({ item_id, item, count }) => ({ item_id, count, name: item.item_name }))
        ] 
      }
    );
    return map;
  }, new Map)
  .values()
];

const groupItemsById = arr => arr.map(e => {
  const items = [...
    e.items.reduce((map, { item_id, name, count }) => {
      const { count: prevCount = 0 } = map.get(item_id) ?? {};
      map.set(item_id, {  item_id, name, count: prevCount + count })
      return map;
    }, new Map)
    .values()
  ]
  return { ...e, items };
});

const group = (arr = []) => {
  const list = groupByDateAndName(arr);
  return groupItemsById(list);
}

const arr = [
  {
    "date": "08/08/2022",
    "name": "Swordsman",
    "items": [
      { "item_id": 1, "item": { "item_name": "Item 1" }, "count": 1 }
    ]
  },
  {
    "date": "08/08/2022",
    "name": "Swordsman",
    "items": [
      { "item_id": 1, "item": { "item_name": "Item 1" }, "count": 2 },
      { "item_id": 2, "item": { "item_name": "Item 2" }, "count": 1 }
    ]
  },
  {
    "date": "08/08/2022",
    "name": "Archer",
    "items": [
      { "item_id": 1, "item": { "item_name": "Item 1" }, "count": 2 },
      { "item_id": 2, "item": { "item_name": "Item 2" }, "count": 1 }
    ]
  }
];
console.log( group(arr) );

1
  • Thanks for taking the time to answer! Commented Aug 21, 2022 at 14:44

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.