I have an array of objects; I have to group objects by same ids, startDates and endDates. If ids are the same but startdate or endDate are NOT the same - do not group there. If startDates or endDates are the same but ids are NOT - do not group there. I've tries to do it with reduce but can't figure out how.
How to do it ?
My code:
const newDates: any[] = [];
response.forEach((elem, index) => {
if(newDates.length === 0) newDates.push([elem])
if(newDates.length > 0) {
if(
newDates[index][0].startDate === elem.startDate
&& newDates[index][0].endDate === elem.endDate
&& newDates[index][0].id === elem.id
) {
newDates[index].push(elem)
} else {
newDates.push([elem])
}
}
})
Example:
const response = [
{
name: 'John',
id: 1,
startDate:'2022-10-31T00:00:00',
endDate: '2022-12-01T00:00:00'
},
{
name: 'Alisha',
id: 1,
startDate:'2022-10-31T00:00:00',
endDate: '2022-12-01T00:00:00'
},
{
name: 'Andrew',
id: 4,
startDate:'2022-10-05T00:00:00',
endDate: '2022-11-01T00:00:00'
},
{
name: 'James',
id: 4,
startDate:'2022-10-05T00:00:00',
endDate: '2022-11-01T00:00:00'
},
{
name: 'Kamilla',
id: 4,
startDate:'2022-11-14T00:00:00',
endDate: '2022-11-18T00:00:00'
},
{
name: 'Oliver',
id: 4,
startDate:'2022-11-13T00:00:00',
endDate: '2022-11-18T00:00:00'
}
]
And result should be
const result = [
[
{
name: 'John',
id: 1,
startDate:'2022-10-31T00:00:00',
endDate: '2022-12-01T00:00:00'
},
{
name: 'Alisha',
id: 1,
startDate:'2022-10-31T00:00:00',
endDate: '2022-12-01T00:00:00'
},
],
[
{
name: 'Andrew',
id: 4,
startDate:'2022-10-05T00:00:00',
endDate: '2022-11-01T00:00:00'
},
{
name: 'James',
id: 4,
startDate:'2022-10-05T00:00:00',
endDate: '2022-11-01T00:00:00'
},
],
[
{
name: 'Kamilla',
id: 4,
startDate:'2022-11-14T00:00:00',
endDate: '2022-11-18T00:00:00'
}
],
[
{
name: 'Oliver',
id: 4,
startDate:'2022-11-13T00:00:00',
endDate: '2022-11-18T00:00:00'
}
]
]
The OP's task belongs to the "group and collect" category.
The approach there is always the same
Thus, as for solving the OP's problem
reduce
the array of items with an initial value which serves as such an index.const { id, startDate, endDate } = item;
const groupKey = [id, startDate, endDate].join('_');
(x ??= y)
operatorpush
the item into the group array.index
into the next iteration step or return it as final result ... return index;
Since the reducer function's result is an object which features the OP's grouped arrays as values of its key-value pairs, this object has to be processed by Object.values
in order to exactly meet the OP's expected data structure (array of arrays of item(s)).
function groupAndCollectItemBySameIdAndDate(index, item) {
const { id, startDate, endDate } = item;
const groupKey = [id, startDate, endDate].join('_');
(index[groupKey] ??= []).push(item);
return index;
}
const sampleData = [{
name: 'John',
id: 1,
startDate:'2022-10-31T00:00:00',
endDate: '2022-12-01T00:00:00'
}, {
name: 'Alisha',
id: 1,
startDate:'2022-10-31T00:00:00',
endDate: '2022-12-01T00:00:00'
}, {
name: 'Andrew',
id: 4,
startDate:'2022-10-05T00:00:00',
endDate: '2022-11-01T00:00:00'
}, {
name: 'James',
id: 4,
startDate:'2022-10-05T00:00:00',
endDate: '2022-11-01T00:00:00'
}, {
name: 'Kamilla',
id: 4,
startDate:'2022-11-14T00:00:00',
endDate: '2022-11-18T00:00:00'
}, {
name: 'Oliver',
id: 4,
startDate:'2022-11-13T00:00:00',
endDate: '2022-11-18T00:00:00'
}];
const groupedData = sampleData
.reduce(groupAndCollectItemBySameIdAndDate, {});
const expectedResult = Object.values(groupedData);
console.log({
groupedData: structuredClone?.(groupedData) ?? groupedData,
expectedResult: structuredClone?.(expectedResult) ?? expectedResult,
});
.as-console-wrapper { min-height: 100%!important; top: 0; }