I have this sample data.
let data = [
{BatchNumber: 1, GroupCode: 'A'},
{BatchNumber: 1, GroupCode: 'A'},
{BatchNumber: 1, GroupCode: 'B'},
{BatchNumber: 1, GroupCode: 'C'},
{BatchNumber: 1, GroupCode: 'B'},
{BatchNumber: 1, GroupCode: 'A'},
{BatchNumber: 2, GroupCode: 'C'},
{BatchNumber: 2, GroupCode: 'B'},
{BatchNumber: 2, GroupCode: 'A'},
{BatchNumber: 2, GroupCode: 'C'}
];
I want to create a two property in this data named countBatch and countGroup.
First, I need to sort data to show them in ascending order and group each data of GroupCode, so I create this method:
data.sort((a, b) => {
if (a.BatchNumber === b.BatchNumber) {
return a.GroupCode.localeCompare(b.GroupCode);
}
return a.BatchNumber - b.BatchNumber;
});
const sortedGroup = {};
data.forEach((item) => {
const key = `${item.BatchNumber}-${item.GroupCode}`;
if (!sortedGroup[key]) {
sortedGroup[key] = [];
}
sortedGroup[key].push(item);
});
Now, I will add property in the data named countGroup, and then show only the counted value in the first data of array each from GroupCode, the rest should be in null value. For example;
{BatchNumber: 1, GroupCode: 'A', countGroup: 3},
{BatchNumber: 1, GroupCode: 'A', countGroup: null},
{BatchNumber: 1, GroupCode: 'A', countGroup: null},
{BatchNumber: 1, GroupCode: 'B', countGroup: 2},
{BatchNumber: 1, GroupCode: 'B', countGroup: null},
{BatchNumber: 1, GroupCode: 'C', countGroup: 1},
{BatchNumber: 2, GroupCode: 'A', countGroup: 1},
{BatchNumber: 2, GroupCode: 'B', countGroup: 1},
{BatchNumber: 2, GroupCode: 'C', countGroup: 2},
{BatchNumber: 2, GroupCode: 'C', countGroup: null}
For the above result I create another method: I iterate over the index of sortedGroup
so I use Object.keys()
function and then I will make a condition that if index is equal to 0, it add value on the property(countGroup). Else, make the value to null.
Here’s the method I created:
var result = [];
Object.keys(sortedGroup).forEach((key) => {
const group = sortedGroup[key];
group.forEach((data, index) => {
if (index === 0) {
data.countGroup = group.length;
} else {
data.countGroup = null;
}
result.push(data);
});
});
Doing the above code, I can now get the result I want.
Here’s a demo.
let data = [
{BatchNumber: 1, GroupCode: 'A'},
{BatchNumber: 1, GroupCode: 'A'},
{BatchNumber: 1, GroupCode: 'B'},
{BatchNumber: 1, GroupCode: 'C'},
{BatchNumber: 1, GroupCode: 'B'},
{BatchNumber: 1, GroupCode: 'A'},
{BatchNumber: 2, GroupCode: 'C'},
{BatchNumber: 2, GroupCode: 'B'},
{BatchNumber: 2, GroupCode: 'A'},
{BatchNumber: 2, GroupCode: 'C'}
];
data.sort((a, b) => {
if (a.BatchNumber === b.BatchNumber) {
return a.GroupCode.localeCompare(b.GroupCode);
}
return a.BatchNumber - b.BatchNumber;
});
const sortedGroup = {};
data.forEach((item) => {
const key = `${item.BatchNumber}-${item.GroupCode}`;
if (!sortedGroup[key]) {
sortedGroup[key] = [];
}
sortedGroup[key].push(item);
});
var result = [];
Object.keys(sortedGroup).forEach((key) => {
const group = sortedGroup[key];
group.forEach((data, index) => {
if (index === 0) {
data.countGroup = group.length;
} else {
data.countGroup = null;
}
result.push(data);
});
});
console.log(result);
Lastly, I will add the property named countBatch in the data. Since the value will count the Batch, I create a variable and a method that count the batch: Here’s the method I used:
const batchCounts = {};
data.forEach((item) => {
if (!batchCounts[item.BatchNumber]) {
batchCounts[item.BatchNumber] = 0;
}
batchCounts[item.BatchNumber]++;
});
And then, add the result of batchCounts
inside the iteration of sortedGroup
. I add variable called batchCount
with value of batchCounts[group[0].BatchNumber]
. This shows the count value of BatchNunber and just pass it to iterattion of group by doing data.countBatch = batchCount;
The PROBLEM is; the value of countBatch is inserted everytime the countGroup value is inserted. I want only to insert the value of countBatch in the first data of each batch number.
CURRENT
let data = [
{BatchNumber: 1, GroupCode: 'A'},
{BatchNumber: 1, GroupCode: 'A'},
{BatchNumber: 1, GroupCode: 'B'},
{BatchNumber: 1, GroupCode: 'C'},
{BatchNumber: 1, GroupCode: 'B'},
{BatchNumber: 1, GroupCode: 'A'},
{BatchNumber: 2, GroupCode: 'C'},
{BatchNumber: 2, GroupCode: 'B'},
{BatchNumber: 2, GroupCode: 'A'},
{BatchNumber: 2, GroupCode: 'C'}
];
data.sort((a, b) => {
if (a.BatchNumber === b.BatchNumber) {
return a.GroupCode.localeCompare(b.GroupCode);
}
return a.BatchNumber - b.BatchNumber;
});
const sortedGroup = {};
data.forEach((item) => {
const key = `${item.BatchNumber}-${item.GroupCode}`;
if (!sortedGroup[key]) {
sortedGroup[key] = [];
}
sortedGroup[key].push(item);
});
const batchCounts = {};
data.forEach((item) => {
if (!batchCounts[item.BatchNumber]) {
batchCounts[item.BatchNumber] = 0;
}
batchCounts[item.BatchNumber]++;
});
var result = [];
Object.keys(sortedGroup).forEach((key) => {
const group = sortedGroup[key];
const batchCount = batchCounts[group[0].BatchNumber];
group.forEach((data, index) => {
if (index === 0) {
data.countBatch = batchCount;
data.countGroup = group.length;
} else {
data.countBatch = null;
data.countGroup = null;
}
result.push(data);
});
});
console.log(result);
EXPECTED
let expected = [
{BatchNumber: 1, GroupCode: 'A', countBatch: 6, countGroup: 3},
{BatchNumber: 1, GroupCode: 'A', countBatch: null, countGroup: null},
{BatchNumber: 1, GroupCode: 'A', countBatch: null, countGroup: null},
{BatchNumber: 1, GroupCode: 'B', countBatch: null, countGroup: 2},
{BatchNumber: 1, GroupCode: 'B', countBatch: null, countGroup: null},
{BatchNumber: 1, GroupCode: 'C', countBatch: null, countGroup: 1},
{BatchNumber: 2, GroupCode: 'A', countBatch: 4, countGroup: 1},
{BatchNumber: 2, GroupCode: 'B', countBatch: null, countGroup: 1},
{BatchNumber: 2, GroupCode: 'C', countBatch: null, countGroup: 2},
{BatchNumber: 2, GroupCode: 'C', countBatch: null, countGroup: null}
];
console.log(expected);
3
Answers
I solve the problem by adding temporary property in data object. Call that property inside the
group
iteration and set the value of countBatch and then, delete the temporary property. Thanks to @Nick Parsons that give me a hint. I still accept his answer.The simplest modification you can probably make to your existing code is to
delete
the current batch number from yourbatchCounts
object and then only add thebatchCount
if you get a number from yourbatchCounts
object:On a side note, I suggest you look at storing your keys in an ES6 Map so that when you iterate the keys, they come out in an expected order in all environments. You can also build
batchCounts
as you buildsortedGroup
object to avoid an additional iteration, eg:Just for the added info. This can be done using
Object.groupBy
when it is widely supported.