Count value frequencies in an array with jQuery - javascript

I have a form with several multiple-choice questions on a page and using serializeArray gives me an array like
[
{
name: "question1",
value: "a"
},
{
name: "question2",
value: "a"
},
{
name: "question3",
value: "b"
}
]
and so on (each question have answer options a, b and c).
How can I count the frequency of each answer (a, b and c) in the array and have the counts as variables (a = 2, b = 1 in the case above)?

You don't need jQuery at all for that.
var array = [
{
name: "question1",
value: "a"
},
{
name: "question2",
value: "a"
},
{
name: "question3",
value: "b"
}
]
var counts = {};
array.forEach(function(element) {
if (!counts[element.value]) {
counts[element.value] = 0;
}
counts[element.value] += 1;
});
console.log(counts);
// Output :
// {"a" : 2, "b" : 1}

Something like that :
var countArray = {}
$.each(dataArray, function(index, value){
if(countArray[value.value] == undefined)
countArray[value.value] = 0;
countArray[value.value]++;
});

Try this : You can iterate the answer array and keep the count in seperate map where answer value is the key. See below code -
var answerArray = [
{
name: "question1",
value: "a"
},
{
name: "question2",
value: "a"
},
{
name: "question3",
value: "b"
}
];
var countMap = {};
$.each(answerArray, function(k, v){
countMap[v.value] = (countMap[v.value])? (parseInt(countMap[v.value])) + 1 : 1;
});
alert(JSON.stringify(countMap));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

simple:
var answers = [
{
name: "question1",
value: "a"
},
{
name: "question2",
value: "a"
},
{
name: "question3",
value: "b"
}
]
var histogram = {};
for ( var n = 0; n <answers.length; n++ )
{
if ( !histogram[answers[n].value] )
histogram[answers[n].value] = 1;
else
histogram[answers[n].value] ++;
}
should give :
{
"a": 2,
"b": 1,
}

Compact jQuery solution:
var count = {a: 0, b: 0, c: 0};
$(array).map(function(){
count[this.value]++;
});
Which gives you in the end:
{a: 2, b: 1, c: 0}

Related

Find objects with same prop and return the update value with its associated prop [duplicate]

I have javascript array object as below. My need is to sum value base on seach id in the array object.
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
],
For example sum of value for id 1 is 10 + 30 + 25 + 20 = 85 , It may be something link linq but I'm not sure in javascript. Thanks for all answers.
You can use a combination of filter and reduce to get the result you want:
sumOfId = (id) => array.filter(i => i.id === id).reduce((a, b) => a + b.val, 0);
Usage:
const sumOf1 = sumOfId(1); //85
Reading material:
Array.prototype.filter
Array.prototype.reduce
A way to do it with a traditional for loop
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
];
var sums = {};
for (var i = 0; i < array.length; i++) {
var obj = array[i];
sums[obj.id] = sums[obj.id] === undefined ? 0 : sums[obj.id];
sums[obj.id] += parseInt(obj.val);
}
console.log(sums);
running example
You can use reduce() and findIndex()
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
];
let res = array.reduce((ac,a) => {
let ind = ac.findIndex(x => x.id === a.id);
ind === -1 ? ac.push(a) : ac[ind].val += a.val;
return ac;
},[])
console.log(res);
JS noob here ... I guess something like this should be here too :-)
let newArray = {}
array.forEach((e) => {
!newArray[e.id] && (newArray[e.id] = 0);
newArray[e.id] += e.val;
});
You can loop on the array and check the ids.
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
];
var sum = 0;
var id = 1;
$.each(array, function(index, object){
if (object.id == id) {
sum += object.val;
}
});
console.log(sum);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Using Array#reduce and Map you can get the sum for each id like so. This also uses destructuring to have quicker access to properties.
const data=[{id:1,val:10},{id:2,val:25},{id:3,val:20},{id:1,val:30},{id:1,val:25},{id:2,val:10},{id:1,val:20}];
const res = data.reduce((a,{id,val})=>{
return a.set(id, (a.get(id)||0) + val);
}, new Map())
console.log(res.get(1));
console.log(res.get(2));
If you wanted to output all the sums, then you need to use Array#from
const data=[{id:1,val:10},{id:2,val:25},{id:3,val:20},{id:1,val:30},{id:1,val:25},{id:2,val:10},{id:1,val:20}];
const res = Array.from(
data.reduce((a,{id,val})=>{
return a.set(id, (a.get(id)||0) + val);
}, new Map())
);
console.log(res);
If the format should be similar as to your original structure, you need to add a Array#map afterwards to transform it.
const data=[{id:1,val:10},{id:2,val:25},{id:3,val:20},{id:1,val:30},{id:1,val:25},{id:2,val:10},{id:1,val:20}];
const res = Array.from(
data.reduce((a,{id,val})=>{
return a.set(id, (a.get(id)||0) + val);
}, new Map())
).map(([id,sum])=>({id,sum}));
console.log(res);
You could take GroupBy from linq.js with a summing function.
var array = [{ id: 1, val: 10 }, { id: 2, val: 25 }, { id: 3, val: 20 }, { id: 1, val: 30 }, { id: 1, val: 25 }, { id: 2, val: 10 }, { id: 1, val: 20 }],
result = Enumerable
.From(array)
.GroupBy(null, null, "{ id: $.id, sum: $$.Sum('$.val') }", "$.id")
.ToArray();
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.js"></script>
Here is another option, introducing an Array.prototype.sum helper:
Array.prototype.sum = function (init = 0, fn = obj => obj) {
if (typeof init === 'function') {
fn = init;
init = 0;
}
return this.reduce(
(acc, ...fnArgs) => acc + fn(...fnArgs),
init
);
};
// .sum usage examples
console.log(
// sum simple values
[1, 2, 3].sum(),
// sum simple values with initial value
[1, 2, 3].sum(10),
// sum objects
[{ a: 1 }, { a: 2 }, { a: 3 }].sum(obj => obj.a),
// sum objects with initial value
[{ a: 1 }, { a: 2 }, { a: 3 }].sum(10, obj => obj.a),
// sum custom combinations
[{ amount: 1, price: 2 }, { amount: 3, price: 4 }]
.sum(product => product.amount * product.price)
);
var array = [{ id: 1, val: 10 }, { id: 2, val: 25 }, { id: 3, val: 20 }, { id: 1, val: 30 }, { id: 1, val: 25 }, { id: 2, val: 10 }, { id: 1, val: 20 }];
// solutions
console.log(
array.filter(obj => obj.id === 1).sum(obj => obj.val),
array.filter(({id}) => id === 1).sum(({val}) => val),
array.sum(({id, val}) => id === 1 ? val : 0)
);
references:
Array.prototype.reduce
Array.prototype.filter
Arrow functions used in sum(obj => obj.val)
Object destructing assignment used in ({id}) => id === 1
Rest parameters used in (acc, ...fnArgs) => acc + fn(...fnArgs)
Conditional (ternary) operator used in id === 1 ? val : 0

How to sum value in javascript array object form specific search id?

I have javascript array object as below. My need is to sum value base on seach id in the array object.
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
],
For example sum of value for id 1 is 10 + 30 + 25 + 20 = 85 , It may be something link linq but I'm not sure in javascript. Thanks for all answers.
You can use a combination of filter and reduce to get the result you want:
sumOfId = (id) => array.filter(i => i.id === id).reduce((a, b) => a + b.val, 0);
Usage:
const sumOf1 = sumOfId(1); //85
Reading material:
Array.prototype.filter
Array.prototype.reduce
A way to do it with a traditional for loop
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
];
var sums = {};
for (var i = 0; i < array.length; i++) {
var obj = array[i];
sums[obj.id] = sums[obj.id] === undefined ? 0 : sums[obj.id];
sums[obj.id] += parseInt(obj.val);
}
console.log(sums);
running example
You can use reduce() and findIndex()
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
];
let res = array.reduce((ac,a) => {
let ind = ac.findIndex(x => x.id === a.id);
ind === -1 ? ac.push(a) : ac[ind].val += a.val;
return ac;
},[])
console.log(res);
JS noob here ... I guess something like this should be here too :-)
let newArray = {}
array.forEach((e) => {
!newArray[e.id] && (newArray[e.id] = 0);
newArray[e.id] += e.val;
});
You can loop on the array and check the ids.
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
];
var sum = 0;
var id = 1;
$.each(array, function(index, object){
if (object.id == id) {
sum += object.val;
}
});
console.log(sum);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Using Array#reduce and Map you can get the sum for each id like so. This also uses destructuring to have quicker access to properties.
const data=[{id:1,val:10},{id:2,val:25},{id:3,val:20},{id:1,val:30},{id:1,val:25},{id:2,val:10},{id:1,val:20}];
const res = data.reduce((a,{id,val})=>{
return a.set(id, (a.get(id)||0) + val);
}, new Map())
console.log(res.get(1));
console.log(res.get(2));
If you wanted to output all the sums, then you need to use Array#from
const data=[{id:1,val:10},{id:2,val:25},{id:3,val:20},{id:1,val:30},{id:1,val:25},{id:2,val:10},{id:1,val:20}];
const res = Array.from(
data.reduce((a,{id,val})=>{
return a.set(id, (a.get(id)||0) + val);
}, new Map())
);
console.log(res);
If the format should be similar as to your original structure, you need to add a Array#map afterwards to transform it.
const data=[{id:1,val:10},{id:2,val:25},{id:3,val:20},{id:1,val:30},{id:1,val:25},{id:2,val:10},{id:1,val:20}];
const res = Array.from(
data.reduce((a,{id,val})=>{
return a.set(id, (a.get(id)||0) + val);
}, new Map())
).map(([id,sum])=>({id,sum}));
console.log(res);
You could take GroupBy from linq.js with a summing function.
var array = [{ id: 1, val: 10 }, { id: 2, val: 25 }, { id: 3, val: 20 }, { id: 1, val: 30 }, { id: 1, val: 25 }, { id: 2, val: 10 }, { id: 1, val: 20 }],
result = Enumerable
.From(array)
.GroupBy(null, null, "{ id: $.id, sum: $$.Sum('$.val') }", "$.id")
.ToArray();
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.js"></script>
Here is another option, introducing an Array.prototype.sum helper:
Array.prototype.sum = function (init = 0, fn = obj => obj) {
if (typeof init === 'function') {
fn = init;
init = 0;
}
return this.reduce(
(acc, ...fnArgs) => acc + fn(...fnArgs),
init
);
};
// .sum usage examples
console.log(
// sum simple values
[1, 2, 3].sum(),
// sum simple values with initial value
[1, 2, 3].sum(10),
// sum objects
[{ a: 1 }, { a: 2 }, { a: 3 }].sum(obj => obj.a),
// sum objects with initial value
[{ a: 1 }, { a: 2 }, { a: 3 }].sum(10, obj => obj.a),
// sum custom combinations
[{ amount: 1, price: 2 }, { amount: 3, price: 4 }]
.sum(product => product.amount * product.price)
);
var array = [{ id: 1, val: 10 }, { id: 2, val: 25 }, { id: 3, val: 20 }, { id: 1, val: 30 }, { id: 1, val: 25 }, { id: 2, val: 10 }, { id: 1, val: 20 }];
// solutions
console.log(
array.filter(obj => obj.id === 1).sum(obj => obj.val),
array.filter(({id}) => id === 1).sum(({val}) => val),
array.sum(({id, val}) => id === 1 ? val : 0)
);
references:
Array.prototype.reduce
Array.prototype.filter
Arrow functions used in sum(obj => obj.val)
Object destructing assignment used in ({id}) => id === 1
Rest parameters used in (acc, ...fnArgs) => acc + fn(...fnArgs)
Conditional (ternary) operator used in id === 1 ? val : 0

Lodash: difference function, but based on JSON format

var b = ["text1", "text2"];
var a = [
{name: "text3", value: 2},
{name: "text4", value: 7},
{name: "text1", value: 4}
];
There is a variety of Lodash functions that I tried, but none of them returning what I want to achieve.
What I want is:
var c = ["text1"]; // uniques from a compared to b
var d = [
{name: "text3", value: 2},
{name: "text4", value: 7}
]; // uniques from b compared to b
You could filter the array and push not unique items.
var b = ["text1", "text2"],
a = [{ name: "text3", value: 2 }, { name: "text4", value: 7 }, { name: "text1", value: 4 }],
c = [],
d = a.filter(({ name }) => !b.includes(name) || !c.push(name));
console.log(c);
console.log(d);
.as-console-wrapper { max-height: 100% !important; top: 0; }
var c = _.reduce(a, (accumulator, item) => {
if(b.indexOf(item.name) !== -1)
accumulator.push(item.name)
return accumulator
}, [])
var d = _.filter(a, (item) => b.indexOf(item.name) === -1)

Get all the objects from a list

So, I have something like this:
objArray1 = [ { candidate1: "Alex" , votes: 4}, { candidate2: "Paul", votes: 3}];
objArray2 = [ { candidate1: "Alex" , votes: 7}, { candidate2: "Ben", votes: 3}, { candidate3: "Melisa", votes:8 }];
I am trying to use javascript to make an array with all the candidates and see how many votes each of them have. The part to calculate the votes is easy, but I don't know how to put all the candidates in one array.
I should get an array with: Alex, Paul, Ben and Melisa.
Thank you!
You could use a hashtable and group by name.
var array1 = [ { candidate1: "Alex" , votes: 4}, { candidate2: "Paul", votes: 3}],
array2 = [ { candidate1: "Alex" , votes: 7}, { candidate2: "Ben", votes: 3}, { candidate3: "Melisa", votes:8 }],
grouped = [array1, array2].reduce(function (hash) {
return function (r, a) {
a.forEach(function (o, i) {
var name = o['candidate' + (i + 1)];
if (!hash[name]) {
hash[name] = { candidate: name, votes: 0 };
r.push(hash[name]);
}
hash[name].votes += o.votes;
});
return r;
};
}(Object.create(null)), []);
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
var candidates = [];
var found = 0;
for(var i=0;objArray1.length>i;i++){
found = 0;
//add votes to candidate array
for(var j=0;candidates.length>j;j++){
if(candidates[j].name==objArray1[i][Object.keys(objArray1[i])[0]]){
candidates[j].votes = candidates[j].votes+objArray1[i].votes;
found = 1;
}
}
//if condidate not found in votes array, create new
if(found==0){
var tmp = {};
tmp.name = objArray1[i].candidate;
tmp.votes = objArray1[i].votes;
//add to array
candidates.push(tmp);
}
}
console.log(candidates);
Generate an object which holds property name as name and vote count as value.
var objArray1 = [ { candidate1: "Alex" , votes: 4}, { candidate2: "Paul", votes: 3}], objArray2 = [ { candidate1: "Alex" , votes: 7}, { candidate2: "Ben", votes: 3}, { candidate3: "Melisa", votes:8 }];
var res = []
// cobine two arrays
.concat(objArray1, objArray2)
// iterate over the arrays
.reduce(function(obj, o) {
// get the key except the votes
var key = Object.keys(o).find(function(k) {
return k != 'votes';
})
// define property if not already defined
obj[key] = obj[key] || 0;
// add the vote count
obj[key] += o.votes;
// return object refernece
return obj;
// set initial value as empty object
}, {});
console.log(res);
// get the names array if need
console.log(Object.keys(res));
Short solution using Array.prototype.concat(), Array.prototype.reduce() and Array.prototype.map() functions:
var objArray1 = [ { candidate1: "Alex" , votes: 4}, { candidate2: "Paul", votes: 3}],
objArray2 = [ { candidate1: "Alex" , votes: 7}, { candidate2: "Ben", votes: 3}, { candidate3: "Melisa", votes:8 }],
grouped = objArray1.concat(objArray2).reduce(function(r, o){
var k = Object.keys(o).filter(function(k){
return k.indexOf('candidate') === 0;
})[0];
(r[o[k]])? r[o[k]].votes += o.votes : r[o[k]] = {candidate: o[k], votes: o.votes};
return r;
}, {}),
result = Object.keys(grouped).map(function(k){ return grouped[k]; });
console.log(result);
To get the list of names as you asked
var rawArrays = objArray1.concat(objArray2), Candidates = [], tmp = []
for (var i in rawArrays) {
tmp[rawArrays[i][Object.keys(rawArrays[i])[0]]] = 1
}
Candidates = Object.keys(tmp)
To get array with candidates and votes sum
var rawArrays = objArray1.concat(objArray2), Candidates = []
for (var i in rawArrays) {
name = rawArrays[i][Object.keys(rawArrays[i])[0]]
if (Candidates[name]) Candidates[name] += rawArrays[i].votes
else Candidates[name] = rawArrays[i].votes
}

Filter object array against another object array

I have two arrays simplified like this.
var a = [{
number: 1,
name: "A"
}, {
number: 2,
name: "B"
}, {
number: 3,
name: "C"
}, {
number: 4,
name: "D"
}, {
number: 5,
name: "E"
}, {
number: 6,
name: "F"
}];
var b = [{
number: 3,
name: "C"
}, {
number: 6,
name: "F"
}];
What I want is to return an array where a is filtered against b. So the result is this.
var result = [{
number: 1,
name: "A"
}, {
number: 2,
name: "B"
}, {
number: 4,
name: "D"
}, {
number: 5,
name: "E"
}];
Have looked at alot of other solutions here on stack overflow but can't get it to work.
I am ok with using libaries like underscore.
It is possible to achieve with lodash by the one-line solution.
var a = [{
number: 1,
name: "A"
}, {
number: 2,
name: "B"
}, {
number: 3,
name: "C"
}, {
number: 4,
name: "D"
}, {
number: 5,
name: "E"
}, {
number: 6,
name: "F"
}];
var b = [{
number: 3,
name: "C"
}, {
number: 6,
name: "F"
}];
var result = _.differenceWith(a, b, _.isEqual);
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
var a = [{
number: 1,
name: "A"
}, {
number: 2,
name: "B"
}, {
number: 3,
name: "C"
}, {
number: 4,
name: "D"
}, {
number: 5,
name: "E"
}, {
number: 6,
name: "F"
}];
var b = [{
number: 3,
name: "C"
}, {
number: 6,
name: "F"
}];
var _ = require('lodash');
var result = _.differenceBy(a,b,'name');
For more informaiton please refer Lodash documentation: https://lodash.com/docs/#differenceBy
You can use Array#filter. Something like that:
const filterData = (a,b) => {
return a.filter( (itemA) => {
return b.some( (itemB) => {
return (itemA.number === itemB.number);
});
});
}
I just created a fiddle to test the code: https://jsfiddle.net/mrlew/pb1qqeyd/3/ (you'll have to open console to check results).
Or... in one-line:
const filterData = (a,b) => a.filter( (itemA) => b.some( (itemB) => (itemA.number === itemB.number) ) );
EDIT: thanks to #kzh suggestions, edited to use .some.
You can use the in-built filter function in JavaScript to filter an array with another array check the below code snippet.
var a = [{
number: 1,
name: "A"
}, {
number: 2,
name: "B"
}, {
number: 3,
name: "C"
}, {
number: 4,
name: "D"
}, {
number: 5,
name: "E"
}, {
number: 6,
name: "F"
}];
var b = [{
number: 3,
name: "C"
}, {
number: 6,
name: "F"
}];
var result = a.filter(function(currentValue, index, arr) {
var found = false;
for (var i = 0; i < b.length; i++) {
if (currentValue.number === b[i].number) {
found = true;
break;
}
}
if (!found) {
return currentValue;
}
});
console.log(result);
You can do this with plain javascript using filter(), some() and every().
var a = [{"number":1,"name":"A"},{"number":2,"name":"B"},{"number":3,"name":"C"},{"number":4,"name":"D"},{"number":5,"name":"E"},{"number":6,"name":"F"}]
var b = [{"number":3,"name":"C"},{"number":6,"name":"F"}]
var result = a.filter(function(o) {
return !b.some(function(e) {
return Object.keys(o).length == Object.keys(e).length && Object.keys(o).every(function(k) {
return e[k] == o[k]
})
})
})
console.log(result)
var v1 = JSON.parse(a);
var v2 = JSON.parse(b);
var v3 = [] ;
function objectEquals(v1, v2) {
if (typeof(v1) !== typeof(v2)) {
return false;
}
if (v1 instanceof Object && v2 instanceof Object) {
for (k in v1) {
r = objectEquals(v1[k], v2[k]);
if (!r) {
v3.push(v1[k]);
}
}
}
}
// call the above method passing your two object, and return a new unique array
objectEquals(v1, v2) ;

Categories