Frequency Counter in array of objects for certain key - javascript

I have an array of objects with students name which are getting repeated often. I want to create a frequency counter of the students name with the number of total counts.
Array :
arr = [
{
name: 'Akshay',
age: '15',
},
{
name: 'Rajat',
age: '14',
},
{
name: 'Akshay',
age: '16',
},
{
name: 'Sam',
age: '12',
},
{
name: 'Akshay',
age: '11',
},
{
name: 'Rajat',
age: '17',
},
{
name: 'Akshay',
age: '12',
},
{
name: 'Sam',
age: '18',
},
{
name: 'Sam',
age: '19',
}
]
I want to get the result like this in an array
result = [
{
name: 'Akshay',
count: 4
},
{
name: 'Rajat',
count: 2
},
{
name: 'Sam',
count: 3
},
]
I tried the below solution but it's not working properly -
const result = arr.reduce((counter,item) => {
var getItem = item.name;
counter[getItem] = counter.hasOwnProperty(getItem) ? counter[getItem] : 1;
return counter;
})
Please help.

You need to pass an accumulator in the reduce. In this case pass an empty object as an accumulator , so the accumulator will look like
{
name:{
name:someName,
count:someCount
},
name2:{
name:someName,
count:someCount
}
}
Once the accumulator is successfully populated, then use Object.values to get an array
const arr = [{
name: 'Akshay',
age: '15',
},
{
name: 'Rajat',
age: '14',
},
{
name: 'Akshay',
age: '16',
},
{
name: 'Sam',
age: '12',
},
{
name: 'Akshay',
age: '11',
},
{
name: 'Rajat',
age: '17',
},
{
name: 'Akshay',
age: '12',
},
{
name: 'Sam',
age: '18',
},
{
name: 'Sam',
age: '19',
}
]
const result = arr.reduce((counter, item) => {
var getItem = item.name;
if (counter.hasOwnProperty(getItem)) {
counter[getItem].count += 1;
} else {
counter[getItem] = {
name: getItem,
count: 1
};
}
return counter;
}, {});
console.log(Object.values(result))

Try this: (you have been missing the initial value)
const count = arr.reduce((prev, cur) => {
prev[cur.name] = (prev[cur.name] || 0) + 1;
return prev;
}, {});
console.log(count);

Related

How to compare the sameness of object entries of 2 arrays and how to create a merger of both objects with custom properties of the found same object?

I am trying to compare 2 objects by their property and the values Strictly using forloop. If the value of the "name" or another property matches up with each other, I want to push the property and value to value3.
Once value3 is logged, I want the response like this:
{
name: 'dog',
surname: 'good',
skills: 'programming',
age: '22'
},
{
name: 'cat',
surname: 'soft',
skills: 'engineer'
age: '12'
},
{
name: 'elephant',
surname: 'big',
skills: 'programming'
age: '23'
}
Here is the code:
var values1 = [
{
name: 'dog',
surname: 'good',
skills: 'programming'
},
{
name: 'cat',
surname: 'soft',
skills: 'engineer'
},
{
name: 'elephant',
surname: 'big',
skills: 'programming'
}
]
var values2 = [
{
name: 'cat',
food: 'fish',
age: '12'
},
{
name: 'elephant',
food: 'leafs',
age: '13'
},
{
lastname: 'dog',
food: 'treats',
age: '22'
}
]
// push into this empty object array
var values3 = [{}]
console.log(values3)
The most generic approach which fulfills all of the OP's requirements should be based on Array.prototype.reduce. Its advantage comes with utilizing the additionally passed optional initial value as kind of configurable collector/accumulator object which will carry all the needed additional information / functions / result. Thus one can provide a reusable function with a customizable context/environment which one can adapt to ones needs.
var values1 = [{
name: 'dog',
surname: 'good',
skills: 'programming',
}, {
name: 'cat',
surname: 'soft',
skills: 'engineer',
}, {
name: 'elephant',
surname: 'big',
skills: 'programming',
}];
var values2 = [{
name: 'cat',
food: 'fish',
age: '12'
}, {
name: 'elephant',
food: 'leafs',
age: '13'
}, {
lastname: 'dog',
food: 'treats',
age: '22'
}];
function mergeItemsOfSameEntry(collector, item) {
const {
getSameEntryValue,
getMergeSubType,
comparisonItems,
result
} = collector;
const itemValue = getSameEntryValue(item);
const comparisonItem = comparisonItems
.find(cItem => getSameEntryValue(cItem) === itemValue);
if (comparisonItem !== null) {
result.push({
...item,
...getMergeSubType(comparisonItem),
});
}
return collector;
}
const values3 = values1.reduce(mergeItemsOfSameEntry, {
getSameEntryValue: item => item.name ?? item.lastname,
getMergeSubType: ({ age }) => ({ age }),
comparisonItems: values2,
result: [],
}).result;
console.log({ values3 });
.as-console-wrapper { min-height: 100%!important; top: 0; }
If you just want the key and value pair, you can do something like this:
var values1 = [
{
name: 'dog',
surname: 'good',
skills: 'programming'
},
{
name: 'cat',
surname: 'soft',
skills: 'engineer'
},
{
name: 'elephant',
surname: 'big',
skills: 'programming'
}
]
var values2 = [
{
name: 'cat',
food: 'fish',
age: '12'
},
{
name: 'elephant',
food: 'leafs',
age: '13'
},
{
lastname: 'dog',
food: 'treats',
age: '22'
}
]
// push into this empty object array
var values3 = [];
values1.forEach(eachValue1Obj => {
const keys = Object.keys(eachValue1Obj);
keys.forEach(eachKey => {
values2.forEach(eachValue2Obj => {
if (
eachValue1Obj[eachKey] &&
eachValue2Obj[eachKey] &&
eachValue1Obj[eachKey] === eachValue2Obj[eachKey]
) {
const x = {
key: eachKey,
value: eachValue1Obj[eachKey]
};
values3.push(x)
}
})
})
})
console.log('Values 3 Array ==>', values3);

How to compare the property of object entries of 2 length arrays and merge into one? [duplicate]

This question already has answers here:
Filter array of objects with another array of objects
(11 answers)
Closed 1 year ago.
I am trying to compare values1 and values2 by their property and the values. If the value of the name property matches up with each other, I want to push the property and value to value3.
But I am getting this error: Cannot read property 'age' of undefined
const values1 = [
{ name: 'dog', surname: 'good', skills: 'programming' },
{ name: 'cat', surname: 'soft', skills: 'engineer' },
{ name: 'elephant', surname: 'big', skills: 'programming' }
]
const values2 = [
{ name: 'cat', age: '12' },
{ name: 'elephant', age: '13' },
]
const values3 = values1.map((value1) => {
return Object.assign(value1, { age: values2.filter(value2 => value2.name === value1.name)[0].age })
})
console.log(values3)
This is the result I would like to return.
{
name: 'cat',
surname: 'soft',
skills: 'engineer'
age: '12'
},
{
name: 'dog',
surname: 'good',
skills: 'programming',
},
{
name: 'elephant',
surname: 'big',
skills: 'programming'
age: '23'
}
You can do it like this:
const values1 = [{
name: 'dog',
surname: 'good',
skills: 'programming'
},
{
name: 'cat',
surname: 'soft',
skills: 'engineer'
},
{
name: 'elephant',
surname: 'big',
skills: 'programming'
}
]
const values2 = [{
name: 'cat',
age: '12'
},
{
name: 'elephant',
age: '13'
},
]
const values3 = values1.map((value1) => {
const sameObj = values2.find(value2 => value2.name === value1.name);
if (sameObj) {
return { ...value1, age: sameObj.age }
}
return value1;
});
console.log(values3)

Comparing 2 objects' values and push the values to one object array

I am trying to compare 2 objects by their property and the values. If the value of the "name" property matches up with each other, I want to push the property and value to value3.
Once value3 is logged, I want the response like this:
{
name: 'dog',
surname: 'good',
skills: 'programming',
age: '22'
},
{
name: 'cat',
surname: 'soft',
skills: 'engineer'
age: '12'
},
{
name: 'elephant',
surname: 'big',
skills: 'programming'
age: '23'
}
Here is the code:
var values1 = [
{
name: 'dog',
surname: 'good',
skills: 'programming'
},
{
name: 'cat',
surname: 'soft',
skills: 'engineer'
},
{
name: 'elephant',
surname: 'big',
skills: 'programming'
}
]
var values2 = [
{
name: 'cat',
food: 'fish',
age: '12'
},
{
name: 'elephant',
food: 'leafs',
age: '13'
},
{
name: 'dog',
food: 'treats',
age: '22'
}
]
// push into this empty object array
var values3 = [{}]
console.log(values3)
const values1 = [
{ name: 'dog', surname: 'good', skills: 'programming' },
{ name: 'cat', surname: 'soft', skills: 'engineer' },
{ name: 'elephant', surname: 'big', skills: 'programming' }
]
const values2 = [
{ name: 'cat', food: 'fish', age: '12' },
{ name: 'elephant', food: 'leafs', age: '13' },
{ name: 'dog', food: 'treats', age: '22' }
]
const values3 = values1.map((value1) => {
return Object.assign(value1, { age: values2.filter(value2 => value2.name === value1.name)[0].age })
})
console.log(values3)
The code above will only work if for each name in values1 an object with name exists in values2. If not use this code:
const values3 = values1.map((value1) => {
const found = values2.find(value2 => value2.name === value1.name)
return Object.assign(value1, { age: found ? found.age : undefined })
})

Map through array, create a key-value pair for each element, and give key of an alphabet letter to each pair

I have an array of objects (I don't know how many object, maybe 3, maybe 10)
example:
const data = [
{name: 'Jane', age: 25},
{name:'Luke', age: 55},
{name:'Martha', age: '16'},
...and so on
]
now I want to map through this array and create a key-value pair for each, and as a key I want to use a letter of alphabet (starting with c).
expected result is:
{
c:{name: 'Jane', age: 25},
d:{name:'Luke', age: 55},
e:{name:'Martha', age: '16'}
...and so on
}
How to achieve that ?
I am using JS & React
You can easily achieve the result using reduce and String.fromCharCode.
ASCII CODE of c is 99
const data = [
{ name: "Jane", age: 25 },
{ name: "Luke", age: 55 },
{ name: "Martha", age: "16" },
];
const result = data.reduce((acc, curr, i) => {
acc[String.fromCharCode(99 + i)] = curr;
return acc;
}, {});
console.log(result);
Disregarding the why, and the limitations of using letters...
You can map the array, and create a tuples of [letter, object], and then convert them to an object using Object.fromEntries().
To create the letter, add 99 to the current index value (i) to get the current letters ascii code, and then convert it to a letter using String.charFromCode().
const data = [
{name: 'Jane', age: 25},
{name:'Luke', age: 55},
{name:'Martha', age: '16'},
]
const result = Object.fromEntries(
data.map((o, i) => [String.fromCharCode(i + 99), o])
)
console.log(result)
You can do that... (with a simple reduce)
const data =
[ { name: 'Jane', age: 25 }
, { name:'Luke', age: 55 }
, { name:'Martha', age: '16'}
]
let lCod = 'c'.charCodeAt(0)
const res = data.reduce((r,o)=>(r[String.fromCharCode(lCod++)]=o,r),{})
console.log (res)
.as-console-wrapper { max-height: 100% !important; top: 0 }
if your array size is bigger than 24...
with the help of georg's answer
const data =
[ { name: 'nam_0', age: 0 }, { name: 'nam_1', age: 1 }, { name: 'nam_2', age: 2 }, { name: 'nam_3', age: 3 }, { name: 'nam_4', age: 4 }
, { name: 'nam_5', age: 5 }, { name: 'nam_6', age: 6 }, { name: 'nam_7', age: 7 }, { name: 'nam_8', age: 8 }, { name: 'nam_9', age: 9 }
, { name: 'nam_10', age:10 }, { name: 'nam_11', age:11 }, { name: 'nam_12', age:12 }, { name: 'nam_13', age:13 }, { name: 'nam_14', age:14 }
, { name: 'nam_15', age:15 }, { name: 'nam_16', age:16 }, { name: 'nam_17', age:17 }, { name: 'nam_18', age:18 }, { name: 'nam_19', age:19 }
, { name: 'nam_20', age:20 }, { name: 'nam_21', age:21 }, { name: 'nam_22', age:22 }, { name: 'nam_23', age:23 }, { name: 'nam_24', age:24 }
, { name: 'nam_25', age:25 }, { name: 'nam_26', age:26 }, { name: 'nam_27', age:27 }, { name: 'nam_28', age:28 }, { name: 'nam_29', age:29 }
]
, cName = ((lZero = 'c')=>
{
let[a,z,Ln] = [...'az'+lZero].map(c=>c.charCodeAt(0)), mod = z-a+1;
Ln -= a;
return ()=>
{
let n = Ln++, s = '';
while (n>=0)
{
s = String.fromCharCode(n % mod + a ) + s
n = Math.floor(n / mod) - 1;
}
return s
} })()
, res = data.reduce((r,o)=>(r[cName()]=o,r),{})
console.log (res)
.as-console-wrapper { max-height: 100% !important; top: 0 }

how to replace array of object with an object in javascript without repeating

let a = [{ name: "ben", age: 25 }, { name: "jeffrey", age: 10 },{ name: "daniel", age: 20 }]
let case1 = { name: "ben", age: 10 }
let case2={ name: "jack", age: 30 }
case1:
i expect the result to be
[{ name: "ben", age: 10 }, { name: "jeffrey", age: 10 },{ name: "daniel", age: 20 }]
where "ben" is existing so it replaces age to 10
case2:
i expect the result to be
[{ name: "ben", age: 25 }, { name: "jeffrey", age: 10 },{ name: "daniel", age: 20 },{ name: "jack", age: 30 }]
where "jack" is not there in the array so it adds to the array
how to write a function which does this functionality
Yours is a good case for Array.prototype.findIndex (MDN), which is like Array.prototype.find but returns the found index instead of the item.
let a = [{ name: "ben", age: 25 }, { name: "jeffrey", age: 10 },{ name: "daniel", age: 20 }]
let case1 = { name: "ben", age: 10 }
let case2 = { name: "jack", age: 30 }
const arrayUpsert = function (array, object) {
const objectIndex = array.findIndex(item => item.name == object.name)
if (objectIndex == -1) {
array.push(object)
} else {
array[objectIndex] = { ...array[objectIndex], ...object }
}
return array
}
console.log(arrayUpsert(a, case1))
console.log(arrayUpsert(a, case2))
/* [
{ name: 'ben', age: 10 },
{ name: 'jeffrey', age: 10 },
{ name: 'daniel', age: 20 }
]
[
{ name: 'ben', age: 10 },
{ name: 'jeffrey', age: 10 },
{ name: 'daniel', age: 20 },
{ name: 'jack', age: 30 }
] */
Can be done with a for loop as well.
function untitled(original, newObj) {
for (let index = 0; index < original.length; index++) {
if (original.name && newObj.name === a[index].name) {
original[index] = {...newObj};
console.log(original); return;
}
}
original.push(newObj); console.log(original);
}
let a = [{ name: "ben", age: 25 }, { name: "jeffrey", age: 10 },{ name: "daniel", age: 20 }]
let case1 = { name: "ben", age: 10 }
let case2 = { name: "jack", age: 30 }
untitled(a, case1);
untitled(a, case2);
I'm using ramda library in my solution:-
Check whether the key exist in any of the object in array by
idx = R.findIndex(R.propEq('name', 'ben'), a). If idx<0 then we can directly push the object else go to the next step.
We have the index(idx), we just have to do a[idx].age="--".

Categories