Count data from jsonObject - javascript

i have this json object array
[{"Subject":"Maths","status:"Pass"},{"Subject":"Maths","status:"Pass"},
{"Subject":"Maths","status:"Fail"},{"Subject":"Maths","status:"Fail"},
{"Subject":"English","status:"Pass"},{"Subject":"English","status:"Fail"}]
I want to count number of pass and fail for each subject and store them in object array like
[{"Subject":"Maths","Pass":2,"Fail":2},"Subject":"English","Pass":2,"Fail":2}]
This data is coming from api also subjects can vary there can be numerous subjects .

Use reduce function and in the accumulator array check if the Subject exist. If it does not exist then create an new object and set the value of key Subject , Pass & Fail.
If it exist then update the value of Pass & Fail
let k = [{
"Subject": "Maths",
"status": "Pass"
},
{
"Subject": "Maths",
"status": "Pass"
},
{
"Subject": "Maths",
"status": "Fail"
},
{
"Subject": "Maths",
"status": "Fail"
},
{
"Subject": "English",
"status": "Fail"
},
{
"Subject": "English",
"status": "Pass"
}
]
let res = k.reduce((acc, curr) => {
let findSubjectIndex = acc.findIndex((item) => {
return item.Subject === curr.Subject;
})
if (findSubjectIndex === -1) {
let crtOb = Object.assign({}, {
Subject: curr.Subject,
Pass: curr.status === "Pass" ? 1 : 0,
Fail: curr.status === "Fail" ? 1 : 0
})
acc.push(crtOb)
} else {
console.table(acc)
acc[findSubjectIndex].Pass = acc[findSubjectIndex].Pass + (curr.status === "Pass" ? 1 : 0);
acc[findSubjectIndex].Fail = acc[findSubjectIndex].Fail + (curr.status === "Fail" ? 1 : 0);
}
return acc;
}, []);
console.log(res)

Use Array.reduce & Object.values
let arr = [{"Subject":"Maths","status":"Pass"},{"Subject":"Maths","status":"Pass"},
{"Subject":"Maths","status":"Fail"},{"Subject":"Maths","status":"Fail"},
{"Subject":"English","status":"Pass"},{"Subject":"English","status":"Fail"}];
// Create an obect with key as subject and value as desired object.
let result = Object.values(arr.reduce((a, {Subject, status}) => {
// if subject exists in object, updating object with count
if(a[Subject]) a[Subject][status] = (a[Subject][status] || 0) + 1;
// else adding a new entry for subject
else a[Subject] = {Subject, [status] : 1};
return a;
}, {}));
console.log(result);

More readable and easy to understand code for newbies like me
var jsonObject = [{"Subject":"Maths","status":"Pass"},{"Subject":"Maths","status":"Pass"},
{"Subject":"Maths","status":"Fail"},{"Subject":"Maths","status":"Fail"},
{"Subject":"English","status":"Pass"},{"Subject":"English","status":"Fail"}];
var passMathCount = 0;
var failMathCount = 0;
var passEnglishCount= 0;
var failEnglishCount = 0;
//Iterate through each object
for(var i = 0; i < jsonObject.length; i++) {
var obj = jsonObject[i];
//Check combination for respective requirements
if(obj.status == "Pass" && obj.Subject == "Maths")
passMathCount++;
else if(obj.status == "Fail" && obj.Subject == "Maths")
failMathCount++;
else if(obj.status == "Pass" && obj.Subject == "English")
passEnglishCount++;
else
failEnglishCount++;
}
//Build json object array
var jsonInstance = [{"Subject": "Maths", "pass": passMathCount, "fail":failMathCount},
{"Subject": "English", "pass": passEnglishCount, "fail":failEnglishCount}];
console.log(jsonInstance);

Related

Unable to get blank properties and it's id from array of object

i want to get empty properties(only need to check role,group and subgroup) and it's id both in array of objects.
let tempdata = [
{
"id": 41,
"tool": "Artifactory",
"role": "",
"group": "Dish",
"subgroup": "Ehub test 009",
"subscriptionId": "artifactory-ehub-test-009"
},
{
"id": 4,
"tool": "Gitlab",
"role": "Owner",
"group": "IDP",
"subgroup": "IDP-Service-Templates",
"subscriptionId": "gitlab-51663585"
}
]
What i tried so far is this:
tempdata.filter(item=>item.group=='' || item.subgroup=='' || item.role=='').map(item=>item.id)
but this only gives my id [41] what i want is [{"id":41,"blank_properties":["role"]}]
Can somebody please help.
you can simply do it this way
tempdata.map((item)=>{
let d = [];
if(item.role === ''){
d.push('role')
}
if(item.group ===''){
d.push('group')
}
if(item.subgroup===''){
d.push('subgroup')
}
return {...item,'blank_prop':d}
})
tempdata.filter(item=>item.group=='' || item.subgroup=='' ||
item.role=='').map(item=>{
let temp=[];
if(item.group==='')temp.push('group')
if(item.role==='')temp.push('role')
if(item.subgroup==='')temp.push('subgroup')
if(item.subscriptionId==='')temp.push('subscriptionId')
if(item.tool==='')temp.push('tool')
return {id:item.id,blank_property:temp};})
I'm going to propose a more sophisticated solution, in case you're interested in additional ways to approach this problem:
let tempData =
[
{
"id": 41,
"tool": "Artifactory",
"role": "",
"group": "Dish",
"subgroup": "Ehub test 009",
"subscriptionId": "artifactory-ehub-test-009"
},
{
"id": 4,
"tool": "Gitlab",
"role": "Owner",
"group": "IDP",
"subgroup": "IDP-Service-Templates",
"subscriptionId": "gitlab-51663585"
},
];
// An array of all properties you want to check for blank strings
const propertiesToCheck = [ "group", "subgroup", "role" ];
result = tempData
.filter((item) =>
{
// Your original code was filtering the array of objects to
// JUST ones that have at least one of those properties set to ""
// So this filter does the same thing.
//
// If you DON'T actually want to outright remove ones that don't match this condition,
// then you can just remove this entire filter step.
// Iterate object keys and values
for (const [ key, value ] of Object.entries(item))
{
// If the key is not in the above array of propertiesToCheck,
// then skip it
if (propertiesToCheck.indexOf(key) == -1)
{
continue;
}
// If we encounter one of those properties and it's blank, return true
if (value == "")
{
return true;
}
}
// Return false if we get through all of the properties without encountering one that's blank
return false;
})
.map((item) =>
{
// Create an object to house the result in the manner you described
const result =
{
id: item.id,
blank_properties: [],
};
// Iterate the object keys and values again
for (const [ key, value ] of Object.entries(item))
{
// Same deal as before
if (propertiesToCheck.indexOf(key) == -1)
{
continue;
}
// Then, if the value is blank...
if (value == "")
{
// ...push its key to the blank_properties array
result.blank_properties.push(key);
}
}
// Return the result!
return result;
});
// Prints:
// [ { id: 41, blank_properties: [ 'role' ] } ]
console.log(result);

Get values for a matching key recursively from object

I have this json object
{
"data": {
"user": {
"user_info": {
"id": "AoGC2HQ9vedHmzcMX"
},
"product": [
{
"node": {
"id": "NzcxNzU2ODU1ODM1",
"feedback": {
"raters": {
"nodes": [
{
"id": "1",
"name": "Dan"
},
{
"id": "2",
"name": "Allen"
},
{
"id": "3",
"name": "Williams"
}
]
},
"commentors": {
"nodes": [
{
"id": "001",
"name": "Kent"
},
{
"id": "002",
"name": "Jay"
}
]
}
}
}
}
]
}
}
}
So how do I make it to get values of id If the parent property matches the desired key name, In this example I want to get all id's from raters.nodes only.
so expected result is
[1,2,3]
I know can do obj.data.user.product[0].node.feedback.raters.nodes and loop through that, but that is not how I want and the object tree occasionally changes.
I have used this recursive function
const recursiveSearch = (obj, searchKey, results = []) => {
const r = results;
Object.keys(obj).forEach(key => {
const value = obj[key];
if(key === searchKey && typeof value !== 'object'){
r.push(value);
}else if(typeof value === 'object'){
recursiveSearch(value, searchKey, r);
}
});
return r;
};
//returns all id's
While it works, it returns all id values, so how do I improve it? If not, how do I make this possible?
I think you want to really do this in 2 steps,..
First make a function to get the root node your looking for, and then you can just use map like normal.
Below is an example.
var data = JSON.parse("{\"data\":{\"user\":{\"user_info\":{\"id\":\"AoGC2HQ9vedHmzcMX\"},\"product\":[{\"node\":{\"id\":\"NzcxNzU2ODU1ODM1\",\"feedback\":{\"raters\":{\"nodes\":[{\"id\":\"1\",\"name\":\"Dan\"},{\"id\":\"2\",\"name\":\"Allen\"},{\"id\":\"3\",\"name\":\"Williams\"}]},\"commentors\":{\"nodes\":[{\"id\":\"001\",\"name\":\"Kent\"},{\"id\":\"002\",\"name\":\"Jay\"}]}}}}]}}}");
function getRoot(data, search) {
function get(path, data) {
for (const [k, v] of Object.entries(data)) {
if (v instanceof Object) {
const pp = `${path}.${k}`;
if (pp.slice(-search.length) === search) {
return v;
}
const r = get(`${path}.${k}`, v);
if (r) return r;
}
}
}
return get('', data);
}
const r = getRoot(data, 'raters.nodes');
console.log(r && r.map(i => i.id));

javascript create nested JSON array from array

I have this array :
myArray = [ "Id = 1", "Time = 18:40", "Topic = yyyyyyyyyyyy", "GUEST", "Role = HS", "Infos = Arizona", "Role = GS", "Infos = Arizona", "Role = GS", "Infos = Colorado", "Id = 2","Time = 11:32", "Topic = xoxo", "GUEST", "Role" = "GS", "Infos = California", "Role = CS", "Infos = Maryland", "Role = GS","Infos = Nevada" ];
I want to create a nested JSON array from it:
myJson = [
{
"Id" : "1",
"Time" : "18:40",
"Topic" : "yyyyyyyyyyyy",
"GUEST":
[
{"Role" : "HS",
"Infos" : "Arizona"},
{"Role" : "GS",
"Infos" : "Arizona"},
{"Role" : "HS",
"Infos" : "Colorado"}
]
},
{
"Id" : "2",
"Time" : "11:32",
"Topic" : "xoxo",
"GUEST":
[
{"Role" : "GS",
"Infos" : "California"},
{"Role" : "CS",
"Infos" : "Maryland"},
{"Role" : "GS",
"Infos" : "Nevada"}
]
}
]
How can I do it? tried the code below without success.
myArray = ["Id = 1","Time = 18:40","Topic = yyyyyyyyyyyy","GUEST","Role = HS","Infos = Arizona","Role = GS","Infos = Arizona","Role = GS","Infos = Colorado","Id = 2","Time = 11:32","Topic = xoxo","GUEST","Role" = "GS","Infos = California","Role = CS","Infos = Maryland","Role = GS","Infos = Nevada"];
// Declaring new object
let obj = {};
// Place to remember current level of object
let level;
myJson = [];
for (let item of this.myArray) {
// If it contains an equals
if (item.includes('=')) {
// Split it into two stings
let split = item.split('=');
let key = split[0].trim();
let val = split[1].trim();
// If we're already on a lower level like GUEST3 put it in there
if (level) {
obj[level][key] = val
} else {
// Or just place the new data at the top level
obj[key] = val
}
} else {
// If there's no equals we want to go down a layer
level = item;
myJson.push(obj[item]);
}
}
console.log("myJson : "+ JSON.stringify(myJson));
Another answer is totally right - format you are requesting is totally wrong. If it would have been just going one object deeper when you meet "GUEST" string and create new object in the output when you meet next "Id = \d+" string, you could use something like:
let process = (arr) => {
let path = [];
const data = [];
let o = data;
while (arr && arr.length) {
let item = arr.shift();
let key= null;
let value = null;
if (/Id = \d+/.test(item)) {
o = {};
data.push(o);
let pair = item.split(' = ');
o.Id = pair[1];
}
else if (item == "GUEST") {
o["GUEST"] = {};
o = o["GUEST"]
value = {};
} else {
let pair = item.split(' = ');
o[pair[0]] = pair[1];
}
}
return data;
}
However with this approach your duplicate keys will get overriden like so:
[
{
"Id": "1",
"Time": "18:40",
"Topic": "yyyyyyyyyyyy",
"GUEST": {
"Role": "GS",
"Infos": "Colorado"
}
},
{
"Id": "2",
"Time": "11:32",
"Topic": "xoxo",
"GUEST": {
"Role": "GS",
"Infos": "Nevada"
}
}
]
I think this is a good start and you can fine tune parsing GUEST part up to your liking
JSON's format is wrong.
Key-value pair array is not allowed in JSON.
Key-value pair array cannot have same name key.
Change to the following format (JSON has strict requirements on the format):
myJson = [
{
"Id" : "1",
"Time" : "18:40",
"Topic" : "yyyyyyyyyyyy",
"GUEST":
[
{
"Role" : "HS",
"Infos" : "Arizona"
},
{
"Role" : "GS",
"Infos" : "Arizona"
},
{
"Role" : "HS",
"Infos" : "Colorado"
}
]
}
]

Removing element from JSON object depending on value

I have a JSON file which looks like so:
{
"2018-1-15 22:35:22": {
"entry": "1234",
"ticket": "32432432432523",
"name": "test"
},
"2018-1-15 23:35:22": {
"entry": "5678",
"ticket": "2485181851981",
"name": "test2"
}
}
And I have this code that checks if an entry value is in the JSON file:
const jsondata = require('./path/to/data.json');
function _isContains(json, value) {
let contains = false;
Object.keys(json).some(key => {
contains = typeof json[key] === 'object' ? _isContains(json[key], value) : json[key] === value;
return contains;
});
return contains;
}
var entryToDelete = 1234
if (_isContains(jsondata, entryToDelete) == true) {
//delete the entire {} for the entryToDelete
}
Basically I would like to delete the element if the entry already exists in the JSON file. So after the deletion of the element, JSON file should look like this:
{
"2018-1-15 23:35:22": {
"entry": "5678",
"ticket": "2485181851981",
"name": "test2"
}
}
I tried to use delete jsondata[entryToDelete];, but that did not delete the element.
Can someone please help me fix this.
Thanks,
Here's your script modified to work as desired:
var jsonData = {
"2018-1-15 22:35:22": {
"entry": "1234",
"ticket": "32432432432523",
"name": "test"
},
"2018-1-15 23:35:22": {
"entry": "5678",
"ticket": "2485181851981",
"name": "test2"
}
}
function _isContains(json, value) {
let contains = false;
Object.keys(json).some(key => {
contains = typeof json[key] === 'object' ? _isContains(json[key], value) : json[key] === value;
return contains = key;
});
return contains;
}
var entryToDelete = 1234
var contains = _isContains(jsonData, entryToDelete)
if ( contains !== false) {
delete jsonData[contains]
console.log(jsonData)
}
const jsondata = {
"2018-1-15 22:35:22": {
"entry": "1234",
"ticket": "32432432432523",
"name": "test"
},
"2018-1-15 23:35:22": {
"entry": "5678",
"ticket": "2485181851981",
"name": "test2"
}
}
function getKeyFromValue(json, value) {
let output = null; // assume we don't find the entry
Object.keys(json).some(key => {
// if entry is equal to value, then set output to key
if ( json[key].entry === value ) output=key;
// return output. As long as it is null, it will continue to with next entry.
return output;
});
return output; // returns the key
}
var entryToDelete = "1234"
var key = getKeyFromValue(jsondata, entryToDelete);
console.log('key', key);
// if the key is set (no need to test for not null)
if (key) delete jsondata[key];
console.log(jsondata);
This is what you need!
var entryToDelete = 1234
for (var key in jsondata) {
if (jsondata.hasOwnProperty(key) && jsondata[key].entry == entryToDelete) {
delete jsondata[key];
}
}

Removing Duplicate object from array in jquery code not working

This is my array in jquery , which contains duplicate objects/elements :
[{
"name": "hello",
"label": "world"
}, {
"name": "abc",
"label": "xyz"
}, {
"name": "hello",
"label": "world"
}]
I am using the following piece of code to remove duplicate elements but it not working the duplicate elements are not removed.
var result = [];
$.each(subservices, function (i, e) {
if ($.inArray(e, result) == -1)
result.push(e);
});
alert(JSON.stringify(result));
Function $.inArray works fine for simple types (e.g. number or string), but for complex types it does not produce the correct result, because it tries to match by reference. Instead of using inArray in your loop you can search the array using function grep:
var subservices = [{
"name": "hello",
"label": "world"
}, {
"name": "abc",
"label": "xyz"
}, {
"name": "hello",
"label": "world"
}
];
var result = [];
$.each(subservices, function (i, e) {
var matchingItems = $.grep(result, function (item) {
return item.name === e.name && item.label === e.label;
});
if (matchingItems.length === 0){
result.push(e);
}
});
//displays result [{"name":"hello","label":"world"},{"name":"abc","label":"xyz"}]
alert(JSON.stringify(result));
Here is a working jsFiddle
You need to filter array by unique name/value. Here is some pure JS solution:
var data = [{
"name": "hello",
"label": "world"
}, {
"name": "abc",
"label": "xyz"
}, {
"name": "hello",
"label": "world"
}];
var result = data.filter(function(el, i, x) {
return x.some(function(obj, j) {
return obj.name === el.name && (x = j);
}) && i == x;
});
alert(JSON.stringify(result, null, 4));
This is because these two objects are distinct, even though all the attributes inside are the same. You can see this from:
console.log(result[0] === result[2]);
which results in false.
Instead, you need to iterate through your array based on a unique identifier, such as name & label as such:
for(var i = 0, i < results.length; i++) {
if (result[i].name === ... && result[i].label === ...) {
index = i;
break;
}
}
to check if your item is unique.

Categories

Resources