0

I'm trying to merge an array of object by removing the ones which have the same code attribute and computing its times attribute.

given the following array:

let itemsTimes = [
    {
        item: {
            code: '0.05'
        },
        times: 1
    },
    {
        item: {
            code: '0.01'
        },
        times: 1
    },
    {
        item: {
            code: '0.02'
        },
        times: 1
    },
    {
        item: {
            code: '0.01'
        },
        times: 1
    },
    {
        item: {
            code: '0.02'
        },
        times: 2
    }
];

and the following code:

let mergedItemTimes = [];

itemsTimes.forEach((itemTime, i) => {
    let j = i + 1
    if ((itemsTimes[j])) {
        itemsTimes.forEach((_, j) => {
            if (itemTime.item.code === itemsTimes[j].item.code) {
                itemTime.times += itemsTimes[j].times
                itemsTimes.splice(j, 1)
            }
        })
    }
    mergedItemTimes.push(itemTime)
})

The expected output it'll be:

[
    { item: { code: '0.05' }, times: 1 },
    { item: { code: '0.01' }, times: 2 },
    { item: { code: '0.02' }, times: 3 },
]

but it's giving me:

[
    { item: { code: '0.05' }, times: 2 },
    { item: { code: '0.02' }, times: 4 },
]

Thanks in advance.

2
  • 2
    Calling splice on an array that you are currently iterating over is rarely a good idea. Commented Aug 16, 2024 at 18:30
  • 1
    You're drastically over-complicating this. Just iterate over the source array and, for each item: (1) If the destination array has a matching item, update it. (2) If it doesn't, add it. Commented Aug 16, 2024 at 18:39

2 Answers 2

2

As you call splice on an array you are iterating, that loop will not visit the next element, because that element shifted to the previous index, and the iteration continues at the next index.

One of the common ways to do this, is with reduce -- not mutating the original objects or array:

const itemsTimes = [{item: {code: '0.05'},times: 1},{item: {code: '0.01'},times: 1},{item: {code: '0.02'},times: 1},{item: {code: '0.01'},times: 1},{item: {code: '0.02'},times: 2}];
const mergedItemTimes = Object.values(
    itemsTimes.reduce((acc, { item: { code }, times }) => {
        (acc[code] ??= { item: { code }, times: 0 }).times += times;
        return acc;
    }, {})
);
console.log(mergedItemTimes);

Sign up to request clarification or add additional context in comments.

Comments

2

I think you are looking for the sum of times where item.code being the key.

   const summary = itemsTimes.reduce((acc, curr) => {
     const accIndex = acc.findIndex((accItem) => accItem.item.code === curr.item.code);
     if (accIndex === -1)
        acc.push(curr);
     if (accIndex >= 0)
        acc.at(accIndex).times += curr.times;
     return acc;
   }, []);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.