JavaScript / jQuery: Compare 2 jSON objects and output result into new object - javascript

I have an api call that replies with an updated jSON object, I also have 1 static jSON object file. I am trying to compare a value in the object per teams with the same name.
So if Team John had 22 in the old file, and has 28 now, the new object should output Team John as 6. Subtracting the 2 and displaying the difference.
I have made a jsFiddle to help understand and update.
LATEST UPDATE: The answer has been solved by mscdeveloper! Check for his post and answer below.
UPDATE (not the answer): I have found a solution while searching in stackoverflow, this does EXACTLY what I want, but I lost the team's name in the process, how can I fix the code to where it doesn't delete it, I know it has something to do with the groupByTypeID function I have?
Updated jsFiddle: https://jsfiddle.net/kqmfsz9n/5/
var obj1 = {
"teams": [
{
name: 'Test 1',
numMembers: '50'
},
{
name: 'Test 2',
numMembers: '12'
}
]
};
var obj2 = {
"teams": [
{
name: 'Test 1',
numMembers: '75'
},
{
name: 'Test 2',
numMembers: '18'
}
]
};
var newObj = {};
function groupByTypeID(arr) {
var groupBy = {};
jQuery.each(arr, function () {
groupBy[this.name] = parseInt(this.numMembers);
});
return groupBy;
}
var userArrayGroups = groupByTypeID(obj2.teams);
var origArrayGroups = groupByTypeID(obj1.teams);
var newObj = [];
for (var prop in userArrayGroups) {
newObj[prop] = userArrayGroups[prop] - origArrayGroups[prop];
newObj.push(userArrayGroups[prop] - origArrayGroups[prop]);
if (newObj[prop] == 0) {
delete newObj[prop];
}
}
console.log(newObj);
All help is appreciated!
Thank you.

var obj1 = {
"teams": [
{
name: 'Test 1',
numMembers: '50'
},
{
name: 'Test 2',
numMembers: '12'
}
]
};
var obj2 = {
"teams": [
{
name: 'Test 1',
numMembers: '75'
},
{
name: 'Test 2',
numMembers: '18'
}
]
};
var newObj = {};
var items_arr=[]; //array of obj2 not exist in obj1
if(obj1.teams){ //if exist array of teams obj1
var o1teams = obj1.teams;
if(obj2.teams){ //if exist array of teams obj2
var o2teams = obj2.teams;
for(var key2 in o2teams){
var o2teams = obj2.teams;
for(var key1 in o1teams){
if(o2teams[key2].name==o1teams[key1].name){
var numMembers_o1_int=parseInt(o1teams[key1].numMembers)||0;
var numMembers_o2_int=parseInt(o2teams[key2].numMembers)||0;
var result_numMembers_int=numMembers_o2_int-numMembers_o1_int;
var result_numMembers=result_numMembers_int+''; //convert to string
var items_for_add=o1teams[key1];
items_for_add.numMembers=result_numMembers;
items_arr.push(items_for_add);
}
}
}
}
}
newObj.items=items_arr;
console.log(newObj);
https://jsfiddle.net/mscdeveloper/uxv1t2a7/3/

Related

Merging contents of an array based on matching content

I am writing some Google Apps Script to get each Google Group and list it's members then output it to a Google Sheet. Currently, I am grabbing each group and email address and pushing it to the memberArr, however I then want to 'merge' the relevant information.
So if for example, I have X Groups and Group 1 has 4 members (Foo, Bar, Baz and Quux) - Currently, it will output as
[ [ 'Group 1', 'Foo' ],
[ 'Group 1', 'Bar' ],
[ 'Group 1', 'Baz' ],
[ 'Group 1', 'Quux' ] ]
But I want to have it output as [Group 1, Foo, Bar, Baz, Quux].
That is to say, merge the contents of the memberArr where there is a common Group
Here is my code so far:
function getAllGroupsTEST() {
const groupArr = [];
let gPageToken;
let gPage;
do {
gPage = AdminDirectory.Groups.list({
customer: "my_customer",
maxResults: 100,
gPageToken
});
const groups = gPage.groups;
if (groups) {
groups.forEach(({email}) => {
const groupEmail = email;
groupArr.push(groupEmail);
});
}
gPageToken = gPage.nextPageToken;
} while (gPageToken);
console.log(`LOGGING GROUPS:\n\n${groupArr}`);
const memberArr = [];
let mPageToken;
let mPage;
groupArr.forEach(group => {
mPage = AdminDirectory.Members.list(group,{
customer: "my_customer",
maxResults: 500,
mPageToken
})
const members = mPage.members;
if (members) {
// console.log(`LOGGING ${members.length} MEMBERS FOR ${group}\n\n${members}`)
members.forEach(member => {
// console.log(`MEMBER: ${member.email} IS IN GROUP ${group}`)
memberArr.push([group, member.email])
})
}
})
// console.log(`COUNTED ${groupArr.length} GROUPS`)
// console.log(memberArr)
}
Any help would be greatly appreciated!
Edit: Updated to show the memberArr as is rather than in a table format.
I'd propose to convert the array in the object and then back to the array this way:
var arr = [
['group1','a'],
['group1','b'],
['group2','c'],
['group2','d'],
['group3','e']
]
var obj = {}
for (var a of arr) {
try { obj[a[0]].push(a[1]) }
catch(e) { obj[a[0]] = [a[1]] }
}
console.log(obj);
var new_arr = [];
for (var group in obj) {
new_arr.push([group, ...obj[group]])
}
console.log(new_arr);
Output:
[ [ 'group1', 'a', 'b' ], [ 'group2', 'c', 'd' ], [ 'group3', 'e' ] ]
I like #YuriKhristich solution. However, I still want to post this code showing how you could make a few minor changes to your existing code to build your required data structure.
We start by initializing a list with the group email. Next we append all the member emails to the list. And finally we push the completed list to memberArr. The advantage is that this builds the required data format while the data is read rather than trying to rework it afterward.
let list = [group]; // <-- ADD
if (members) {
members.forEach(member => {
// memberArr.push([group, member.email]) <-- REMOVE
list.push(member.email); // <-- ADD
})
memberArr.push(list); // <-- ADD
}
})
// Simulated Google Groups data
var gPage = {
groups: [
{id: 1, name: "Group 1", email: "group1#emal.com" },
{id: 2, name: "Group 2", email: "group2#emal.com" },
{id: 3, name: "Group 3", email: "group3#emal.com" }
]
};
var mPage = {
members: [
{id: 1, role: "admin", email: "member1#email.com" },
{id: 2, role: "admin", email: "member2#email.com" },
{id: 3, role: "admin", email: "member3#email.com" },
{id: 4, role: "admin", email: "member4#email.com" },
{id: 5, role: "admin", email: "member5#email.com" }
]
};
function getAllGroupsTEST() {
const groupArr = [];
let gPageToken;
//let gPage;
do {
/* useing fake data
gPage = AdminDirectory.Groups.list({
customer: "my_customer",
maxResults: 100,
gPageToken
});
*/
const groups = gPage.groups;
if (groups) {
groups.forEach(({email}) => {
const groupEmail = email;
groupArr.push(groupEmail);
});
}
gPageToken = gPage.nextPageToken;
} while (gPageToken);
const memberArr = [];
let mPageToken;
//let mPage;
groupArr.forEach(group => {
/* using fake data
mPage = AdminDirectory.Members.list(group,{
customer: "my_customer",
maxResults: 500,
mPageToken
})
*/
const members = mPage.members;
let list = [group];
if (members) {
members.forEach(member => {
// memberArr.push([group, member.email])
list.push(member.email);
})
memberArr.push(list);
}
})
return memberArr;
}
console.log( getAllGroupsTEST() );
You can implement this easy function for every group you want to filter
Take into account that this will eliminate every duplicate of the array.
const dataToFiler = [['Group 1', 'Foo'],
['Group 1', 'Bar'],
['Group 1', 'Baz'],
['Group 1', 'Quux']]
const filterRD = (arr) => {
return [...new Set(arr.flat())]
}
console.log(filterRD(dataToFiler))
Documentation
Set
Array.prototype.flat()

How to add an object as a field to another existing object in JavaScript

I am new to JS and I am trying to do a basic operation on a JS object.
I have the following object:
var originalObj = {
id: 1,
name: 'originalObj'
}
Now I would like to add another object as a field to originalObj.
var newObj = {
newId: 2,
name: 'newObj'
}
So expected outcome is:
orginalObj = {
id: 1,
name: 'originalObj',
newObj: {
newId: 2,
name: 'newObj'
}
}
What I tried so far:
originalObj.newObj = newObj and originalObj['newObj'] = newObj
This results in:
orginalObj = {
id: 1,
name: 'originalObj',
newObj:
}
Object.assign(originalObj, newObj)
This add all the fields of newObj on the same level as originalObj. Like below:
originalObj = {
id: 1,
name: 'originalObj',
newId: 2,
name: 'newObj'
}
Depends on if you want a deep copy or just a reference.
originalObj.newObj = newObj; will assign a reference to newObj where as
originalObj.newObj = Object.assign({}, newObj); will create a new one.
Note: if your using ECMAScript 2015 (6th Edition, ECMA-262) you can use the spread operator ...
originalObj.newObj = {...newObj};
Example: https://jsbin.com/yisiyip/edit?js,console
originalObj.newObj=newObj; //this should do the job
const originalObj = {
id: 1,
name: 'originalObj'
}
const newObj = {
newId: 2,
name: 'newObj'
}
originalObj = { ...originalObj, newObj }
what's happening here is you are spreading the values of originalObj into an empty object together with the value of newObj by shorthand method
reference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer

JS HighCharts.js Pie data undefined error in code

I am having a bit of an issue with the following code:
//The Code:
var data = [];
for (var i = 0; i < mydata.length; i++) { //looping through data received
var obj = mydata[i]; //current obj in loop
var newObj = { //creating new obj with same structure as the 'data' that works
name: obj.name,
y: obj.subhere.subhere1,
id: i
};
data.push(newObj); //pushing each object into the data array
}
//THE DATA:
var data = [{ name: 'Name 1', y: 20, id: 0 },{ name: 'Name 2', y: 10, id: 1 },{ name: 'Name 3', y: 10, id: 2 }];
//THE CHART CODE:
chart = new Highcharts.Chart({
series:[
{
"data": data,
type: 'pie',
animation: false,
point:{
events:{
click: function (event) {
//alert(this.id);
}
}
}
}
],
"chart":{
"renderTo":"container"
},
});
//The above with create a pie chart with 3 names
//The Data
var mydata =[{
"001":{
"name":"Name 1",
"subhere":{
"subhere1":2
}
},
"002":{
"name":"Name 2",
"subhere":{
"subhere1":20
}
},
}];
The console is giving me the following error:
TypeError: obj.subhere is undefined y: obj.subhere.subhere1,
I can see that the subhere.subhere1 names actually exists so in theory it should not be giving me an error, right?.
How can I fix this issue ... any ideas?
myData doesn't look correctly formatted. It has an extra comma after the bracket before last:
},
}];
You can loop through your object properties:
var data = [];
for (var i = 0; i < mydata.length; i++) { //looping through data received
var obj = mydata[i]; //current obj in loop
for(var key in obj){
var newObj = { //creating new obj with same structure as the 'data' that works
name: obj[key].name,
y: obj[key].subhere.subhere1,
id: i
};
data.push(newObj); //pushing each object
}
}
To work with your existing code, you could change the definition of mydata to this:
var mydata =[
{
"name":"Name 1",
"subhere":{
"subhere1":2
}
},
{
"name":"Name 2",
"subhere":{
"subhere1":20
}
}
];

Dynamically drill down nested array of objects

How can I dynamically drill down my array of objects? Let me explain. Say I have this array of objects with subarrays:
var arrOfObjects = [
{
name: 'something',
subArray: [ {
name: 'nested something'
} ]
},
{
name: 'something else',
subArray: [ {
name: 'nested something else'
} ]
}];
and a reference to know which array in the hierarchy I need to modify
var referenceArr = [1,0];
How do I use this reference to generate the proper location in my data array, in this case, I would want to get to
arrOfObject[1]['subArray][0]['name'];
// 'subArray' and 'name' are always the same
The reference array could be any length, so
var referenceArr= [0];
indicates modifying:
arrOfObject[0]['name'];
Use this function:
function getValue(source, path){
var result = source;
while(path.length){
result = result[path.shift()];
if(path.length && !result.subArray)
throw new Error('Incorrect path!');
else if(path.length)
result = result.subArray;
else
result = result.name;
}
return result;
}
fiddle
Try this Check this jsfiddle
var arrOfObjects = [
{
name: 'something',
subArray: [ {
name: 'nested something'
} ]
},
{
name: 'something else',
subArray: [ {
name: 'nested something else'
} ]
}];
for(var i=0; i<arrOfObjects.length;i++){
alert(arrOfObjects[i].subArray[0].name)
}

Javascript: How convert array of objects to object with sorted unique arrays?

Have data that has this kind of structure:
$input = [ { animal: 'cat', name: 'Rocky', value: 1 },
{ animal: 'cat', name: 'Spot', value: 2 },
{ animal: 'dog', name: 'Spot', value: 3 } ];
Need fastest possible method for converting to this format:
$output = { animal: [ 'cat', 'dog' ],
name: [ 'Rocky', 'Spot' ],
value: [ 1, 2, 3 ] };
The output should have keys equal to each of the keys in each object from the input. And the output values should be arrays with the sorted unique values. I found a few ways to do it using nested loops, but slower than I would like. With 30,000 elements to the input array with 8 keys for each of the objects, the best I have been able to do is 300ms in Chrome. Would like to get down to 100ms. Is there any faster method using a map or reduce?
Yet another way for modern browsers:
$input.reduce(function(acc, obj) {
Object.keys(obj).forEach(function(k) {
acc[k] = (acc[k] || []).concat(obj[k])
})
return acc
},{})
Here's one way.
$input = [ { animal: 'cat', name: 'Rocky', value: 1 },
{ animal: 'cat', name: 'Spot', value: 2 },
{ animal: 'dog', name: 'Spot', value: 3 } ];
$output = {animal:{},name:{},value:{}};
$input.forEach(function(v,i) {
$output.animal[v.animal] = 1;
$output.name[v.name] = 1;
$output.value[v.value] = 1;
});
$output.animal = Object.keys($output.animal);
$output.name = Object.keys($output.name);
$output.value = Object.keys($output.value);
It prevents having to test each Array every time. You can performance compare to see if it helps.
live example: http://jsfiddle.net/TJVtj/1/
If you don't want to hardcode the keys, you can make the solution generic.
var keys = Object.keys($input[0]),
$output = {};
keys.forEach(function(v) {
$output[v] = {};
});
$input.forEach(function(v) {
keys.forEach(function(vv) {
$output[vv][v[vv]] = 1;
});
});
keys.forEach(function(v) {
$output[v] = Object.keys($output[v]);
});
live example: http://jsfiddle.net/TJVtj/2/
Warning. All the values will be strings since they're fetched as object keys.
function inArray(needle, haystack) {
var length = haystack.length;
for(var i = 0; i < length; i++) {
if(haystack[i] == needle) return true;
}
return false;
}
Above function is used to check duplicates
$output={};
for(i=0; i< $input.length; i++)
{
if(!$output.animal) $output.animal=[];
if(!$output.name) $output.name=[];
if(!$output.value) $output.value=[];
var ani=$input[i];
if(ani.animal && !inArray(ani.animal, $output.animal)) $output.animal.push(ani.animal);
if(ani.name && !inArray(ani.name, $output.name)) $output.name.push(ani.name);
if(ani.value) $output.value.push(ani.value);
}
DEMO.
// If you don't know the objects all have the same keys you need to look at each one-
var output= {},
input= [{
animal:'cat', name:'Rocky', value:1
},{
animal:'cat', name:'Spot', value:2
},{
animal:'dog', name:'Spot', value:3
}];
input.forEach(function(itm){
for(var p in itm){
if(itm.hasOwnProperty(p)){
if(!output[p]) output[p]= [];
if(output[p].indexOf(itm[p])== -1) output[p].push(itm[p]);
}
}
});
Run.expose(output)// nonstandard object to string method
// returned value: (String)
{
animal:[
'cat',
'dog'
],
name:[
'Rocky',
'Spot'
],
value:[
1,
2,
3
]
}
Try Underscore, it's magnificent with this kind of tasks)

Categories

Resources