1

I have referred to this article

I have the following code:

var testArrys = [
{ attrName: 'life', p_id:19, num:1, name: 'milk'},
{ attrName: 'food', p_id:20, num:1, name: 'apple'},
{ attrName: 'life', p_id:19, num:2, name: 'milk'},
{ attrName: 'life', p_id:22, num:1, name: 'egg'},
{ attrName: 'clothes', p_id:21, num:1, name: 'coat'},
]

Divide the different arrays according to attrName, add num according to whether p_id is the same, Delete more than p_id objects

I tried the following:

function groupBy(list, keyGetter) {
    const map = new Map();
    list.forEach((item) => {
         const key = keyGetter(item);
         const collection = map.get(key);
         if (!collection) {
             map.set(key, [item]);
         } else {
             collection.push(item);
         }
    });
    return map;
}
const grouped = groupBy(testArrys, attr => attr.attrName);

I tried, but I couldn't achieve what I wanted

I want the following results:

var result = [
  [
    { attrName: 'life', p_id:19, num:3, name: 'milk'},
    { attrName: 'life', p_id:22, num:1, name: 'egg'},
  ],
  [
    { attrName: 'food', p_id:20, num:1, name: 'apple'}
  ],
  [
    { attrName: 'clothes', p_id:21, num:1, name: 'coat'}
  ],
]
2

3 Answers 3

2

You could check for the same p_id in the collection and add num value to the existing property. By mutating the object, I suggest to use a copy of item.

At the end, return the values from the Map.

For a dynamic approach, you could specify a function for getting the item with the wanted sub key in the same group and perform either the same property or different, depending on the find.

function groupBy(list, keyGetter, sub) {
    const map = new Map();
    list.forEach(({ ...item }) => {
         const key = keyGetter(item);
         const collection = map.get(key);
         if (!collection) {
             map.set(key, [item]);
             return;
         }
         if (!sub) {
             collection.push(item);
             return;
         }
         var temp = collection.find(o => sub.key(o) === sub.key(item));
         if (temp) {
             sub.same(item, temp);
         } else {
             sub.different(item, collection);
         }
    });
    return Array.from(map.values()); // return values only
}

var testArrys = [{ attrName: 'life', p_id:19, num:1, name: 'milk' }, { attrName: 'food', p_id:20, num:1, name: 'apple' }, { attrName: 'life', p_id:19, num:2, name: 'milk' }, { attrName: 'life', p_id:22, num:1, name: 'egg' }, { attrName: 'clothes', p_id:21, num:1, name: 'coat' }]

const
    grouped = groupBy(
        testArrys,
        attr => attr.attrName,
        {
            key: item => item.p_id,
            same: (source, target) => target.num += source.num,
            different: (source, target) => target.push(source)
        }
    );

console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

2 Comments

OP wants to add up the num if attrName and p_id are same.
@NinaScholz Thank you very much for the answer, what if I want to add a new parameter dynamically?
2

You can use Array.prototype.reduce.

const testArrys = [
	{ attrName: 'life', p_id: 19, num: 1, name: 'milk' },
	{ attrName: 'food', p_id: 20, num: 1, name: 'apple' },
	{ attrName: 'life', p_id: 19, num: 2, name: 'milk' },
	{ attrName: 'life', p_id: 22, num: 1, name: 'egg' },
	{ attrName: 'clothes', p_id: 21, num: 1, name: 'coat' },
]

let out = [...testArrys.reduce((acc, curr) => {
	if (acc.has(curr.attrName)) {
		if (acc.get(curr.attrName)[0].p_id === curr.p_id) {
			acc.set(curr.attrName, [{ ...curr, num: acc.get(curr.attrName)[0].num + curr.num }]);
		} else {
			acc.get(curr.attrName).push(curr)
		}
	} else {
		acc.set(curr.attrName, [curr])
	}
	return acc;
}, new Map()).values()];

console.log(out)

If you want to use multiple parameters for merging you use Array.prototype.every to check if values for each key matches then only merge.

const testArrys = [
	{ attrName: 'life', p_id: 19, num: 1, name: 'milk' },
	{ attrName: 'food', p_id: 20, num: 1, name: 'apple' },
	{ attrName: 'life', p_id: 19, num: 2, name: 'milk' },
	{ attrName: 'life', p_id: 22, num: 1, name: 'egg' },
	{ attrName: 'clothes', p_id: 21, num: 1, name: 'coat' },
]

let out = [...testArrys.reduce((acc, curr) => {
	if (acc.has(curr.attrName)) {
		if (checkEqual(acc.get(curr.attrName)[0], curr, ['p_id', 'name'])) {
			acc.set(curr.attrName, [{ ...curr, num: acc.get(curr.attrName)[0].num + curr.num }]);
		} else {
			acc.get(curr.attrName).push(curr)
		}
	} else {
		acc.set(curr.attrName, [curr])
	}
	return acc;
}, new Map()).values()];

function checkEqual(a, b, keys) {
	return keys.every(k=> a[k]=== b[k])
}
console.log(out)

Comments

0
 Object.values(testArrys.reduce((items , item)=>{
  if(items[item.attrName])
    items[item.attrName].push(item)
  else
   items[item.attrName]= [item]

  return items
}
,{}))

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.