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)
Related
I have two array of objects with no common properties:
let a = [
{id: 1},
{id: 2},
{id: 3},
];
let b = [
{day: 12},
{day: 15}
];
I want to merge the props of b into a. Initially, I tried
let m = a.map((i,x) => ({id: i.id, day: b[x].day}));
This worked just fine as long as the lengths of both the arrays were the same. But when b was shorter or a was shorter, that would result in an error
Uncaught TypeError: Cannot read properties of undefined (reading 'day')
I don't really care about the length of b, all I want is a, and if b has an element at the same index, I want that b.day.
I ended up doing this:
let a = [
{id: 1},
{id: 2},
{id: 3},
];
let b = [
{day: 12},
{day: 15}
];
let m = [];
a.forEach((i, x) => {
let item = { id: i.id };
if (b.length > x) {
item['day'] = b[x].day;
}
m.push(item);
});
console.log(m);
This works fine, but it is decidedly uncool. I know this is probably more readable, but, go with me on this one.
Is there a way to make this more ES6 friendly? Is there a shorter / more concise way of achieving this please?
You could map the properties with spreading. If value at index is undefined, it acts like an empty object.
const
a = [{ id: 1 }, { id: 2 }, { id: 3 }],
b = [{ day: 12 }, { day: 15 }],
m = a.map((o, i) => ({ ...o, ...b[i] }));
console.log(m);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If I understood your question correctly.
A simple way of merging 2 arrays while also merging the objects at the same index:
let a = [{ id: 1 }, { id: 2 }, { id: 3 }];
let b = [{ day: 12 }, { day: 15 }];
let m = [];
//merge a and b together in m
m = a.map((item, index) => (b[index] ? { ...item, ...b[index] } : item));
console.log(m);
//output
m= [
{
"id": 1,
"day": 12
},
{
"id": 2,
"day": 15
},
{
"id": 3
}
]
Create a new array with the maximum length of both arrays. Loop through this array and return the objects from both a and b array.
let a = [{ id: 1 }, { id: 2 }, { id: 3 }];
let b = [{ day: 12 }, { day: 15 }];
const dummyArray = new Array(Math.max(a.length, b.length)).fill(0)
let m = dummyArray.map((_, index) => ({...a[index], ...b[index]}));
console.log(m);
I'd like to create this structure:
{
"officine_type": "Pharmacie",
"officine_value": 2002626,
"declared_lines": [
{
"ean": 3578835501148,
"qty": 1
},
{
"ean": 3578835502671,
"qty": 2
}
],
"other_value": "my other value"
}
From a serializeArray() with this output:
0: {name: 'declared_lines.0.ean', value: '3578835502244'}
1: {name: 'declared_lines.0.qty', value: '4'}
2: {name: 'declared_lines.1.ean', value: '3578835502220'}
3: {name: 'declared_lines.1.qty', value: '1'}
4: {name: 'declared_lines.2.ean', value: ''}
5: {name: 'declared_lines.2.qty', value: '0'}
6: {name: 'officine_type', value: 'Pharmacy'}
7: {name: 'officine_value', value: '2000461'}
8: {name: 'other_value', value: ''}
I'm struggling on how to push sub-objects in declared_lines
Right now i have this:
let formData = form.serializeArray();
for (let i = 0; i < formData.length; i++) {
if (formData[i]['name'].indexOf('declared_lines') !== 1) {
let inputName = formData[i]['name'].split('.');
let namespace = inputName[0];
let n = inputName[1];
let key = inputName[2];
let subObj = {};
let current = 'declared_lines['+i+']';
let previous = 'declared_lines['+(i-1)+']';
if (obj.hasOwnProperty(namespace) === false) {
obj[namespace] = [];
}
}
obj[formData[i]['name']] = formData[i]['value'];
}
My brain won't go further :(
You could take the name and split it by dot for the path of the new object and the value and build a new object with the given information.
In setValue, the reduce callback checks if the next key is a stringed numerical value and takes an array as default object instead of an object.
function setValue(object, path, value) {
const last = path.pop();
path
.reduce((o, k, i, kk) => o[k] ??= (isFinite(i + 1 in kk ? kk[i + 1] : last) ? [] : {}), object)
[last] = value;
return object;
}
const
data = [{ name: 'declared_lines.0.ean', value: '3578835502244' }, { name: 'declared_lines.0.qty', value: '4' }, { name: 'declared_lines.1.ean', value: '3578835502220' }, { name: 'declared_lines.1.qty', value: '1' }, { name: 'declared_lines.2.ean', value: '' }, { name: 'declared_lines.2.qty', value: '0' }, { name: 'officine_type', value: 'Pharmacy' }, { name: 'officine_value', value: '2000461' }, { name: 'other_value', value: '' }],
result = data.reduce(
(object, { name, value }) => setValue(object, name.split('.'), value),
{}
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Object destructuring and array.reduce can make your code more readable, try:
let formData = [
{name: 'declared_lines.0.ean', value: '3578835502244'},
{name: 'declared_lines.0.qty', value: '4'},
{name: 'declared_lines.1.ean', value: '3578835502220'},
{name: 'declared_lines.1.qty', value: '1'},
{name: 'declared_lines.2.ean', value: ''},
{name: 'declared_lines.2.qty', value: '0'},
{name: 'officine_type', value: 'Pharmacy'},
{name: 'officine_value', value: '2000461'},
{name: 'other_value', value: ''}
];
let output = formData.reduce((acc,cur) => {
let { name, value } = cur;
if(name.indexOf('declared_lines') === -1){
acc[name] = value;
} else {
let [namespace, n, key] = name.split('.');
if(!acc[namespace]) acc[namespace] = [];
if(!acc[namespace][n]) acc[namespace][n] = {};
acc[namespace][n][key] = value;
}
return acc;
}, {});
console.log(output);
In this case reduce starts with an empty object and it loops over your array to process each element (cur).
I have a simple question. I have two arrays A and B, I want to retain A objects if B has the same ID.
For example:
const A = [{id: "price", value: "1"}]
const B = [{id: "price", value: "0"}, {id: "number", value: "0"}]
Expected result:
[{id: "price", value: "1"}, {id: "number", value: "0"}}]
How can I do this?
I tried to map A and foreach B inside A but it didn't work.
const result = A.concat(B.filter(bo => A.every(ao => ao.id != bo.id)));
Concatenate all the objects from A with objects from B that aren't in A (which is done by filtering only objects from B where there isn't an object in A with the same id).
Example:
const A = [{id: "price", value: "1"}];
const B = [{id: "price", value: "0"}, {id: "number", value: "0"}];
const result = A.concat(B.filter(bo => A.every(ao => ao.id != bo.id)));
console.log(result);
You'd use reduce on the merged array - also turn the value into a number:
const A = [{id: "price", value: "1"}];
const B = [{id: "price", value: "0"}, {id: "number", value: "0"}];
const res = Object.values([...A, ...B].reduce((acc, { id, value }) => {
if (acc[id]) acc[id].value += parseInt(value);
else acc[id] = { id, value: parseInt(value) };
return acc;
}, {}));
console.log(res);
.as-console-wrapper { max-height: 100% !important; top: auto; }
Another option that you could try (I believe it would be O(n) ) is to convert arrays to objects with id as key then extend (jquery.extend or pure js implementation) then convert the merged object back to array.
const A = [{id: "price", value: "1"}];
const B = [{id: "price", value: "0"}, {id: "number", value: "0"}];
//convert arrays to objects
var Bx = {};
B.forEach(i => Bx[i.id] = i);
var Ax = {};
A.forEach(i => Ax[i.id] = i);
//copy all matching id properties from A to B
A.forEach(i => Bx[i.id] = Ax[i.id]);
//convert the merged object to array
var C = [];
Object.getOwnPropertyNames(Bx).forEach(i => C.push(Bx[i]));
console.log(C);
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
}
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}