skip to Main Content

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


  1. Chosen as BEST ANSWER

    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.

    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, index) => {
        item.tempBatchCount = batchCounts[item.BatchNumber] //added this line;
        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) => {
            data.countBatch = !(data.tempBatchCount) ? batchCount : null; //added this line;
            delete data.tempBatchCount; //added this line;
            if (index === 0) {
                data.countGroup = group.length;
            } else {
                data.countGroup = null;
            }
            result.push(data);
        });
    });
    console.log(result);


  2. The simplest modification you can probably make to your existing code is to delete the current batch number from your batchCounts object and then only add the batchCount if you get a number from your batchCounts object:

    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];
        group.forEach((data, index) => {
            const batchCount = batchCounts[group[0].BatchNumber];    
            if(batchCount != undefined) {
              delete batchCounts[group[0].BatchNumber];
              data.countBatch = batchCount;
            } else {
              data.countBatch = null;
            }
            
        
            if (index === 0) {
                data.countGroup = group.length;
            } else {
                data.countGroup = null;
            }
            result.push(data);
        });
    });
    console.log(result);

    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 build sortedGroup object to avoid an additional iteration, eg:

    const sortedGroup = {};
    const batchCounts = {};
    data.forEach((item) => {
        const key = `${item.BatchNumber}-${item.GroupCode}`;
        batchCounts[item.BatchNumber] = (batchCounts[item.BatchNumber] || 0) + 1;
        if (!sortedGroup[key]) {
            sortedGroup[key] = [];
        }
        sortedGroup[key].push(item);
    });
    
    Login or Signup to reply.
  3. Just for the added info. This can be done using Object.groupBy when it is widely supported.

    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;
    });
    
    // defines what attribute needs to be added based on keys
    const attributes = {
      countGroup: ['BatchNumber', 'GroupCode'],
      countBatch: ['BatchNumber']
    }
    
    Object.entries(attributes).forEach(([key, identifiers]) => {
      Object.values(Object.groupBy(data, item => identifiers.map(id => item[id]).join())).forEach(group => {
        group.forEach((item, i) => item[key] = i ? null : group.length);
      });
    });
    
    console.log(data);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search