Reduce JSON array to object with combined key-values - javascript

I have an array like this:
[
{ "avl_res": 1, "res_status": "Available", "code": "AAA" },
{ "avl_res": 2, "res_status": "Unavailable", "code": "AAA" },
{ "avl_res": 2, "res_status": "Available", "code": "BBB" },
{ "avl_res": 1, "res_status": "Available", "code": "CCC" },
{ "avl_res": 5, "res_status": "Unavailable", "code": "CCC" },
{ "avl_res": 3, "res_status": "Unavailable", "code": "DDD" },
];
I am trying to produce this:
[
{"avl_res":1,"total_res":3,"code":"AAA"},
{"avl_res":2,"total_res":2,"code":"BBB"},
{"avl_res":1,"total_res":6,"code":"CCC"},
{"avl_res":0,"total_res":3,"code":"DDD"},
];
Following the answer to this question, I managed to do it with this:
var singles = {};
arr.forEach(function (item) {
var single = singles[item.code] = singles[item.code] || {};
single[item.res_status] = item.avl_res;
});
var outputList = [];
for (var single in singles) {
let total_res = 0;
let avl_res = 0;
singles[single]['Available'] ? avl_res = singles[single]['Available'] : avl_res = 0;
singles[single]['Unavailable'] ? total_res = avl_res + singles[single]['Unavailable'] : total_res = avl_res;
outputList.push({ code: single, total_res: total_res, avl_res: avl_res });
}
console.log(outputList);
Just wondering if this is efficient enough or there's a better/elegant way, maybe by using other JS functions (e.g. reduce, map, etc.). Cheers!

If you care code performance (efficiency) that much, You would like this...
const arr = [
{ "avl_res": 1, "res_status": "Available", "code": "AAA" },
{ "avl_res": 2, "res_status": "Unavailable", "code": "AAA" },
{ "avl_res": 2, "res_status": "Available", "code": "BBB" },
{ "avl_res": 1, "res_status": "Available", "code": "CCC" },
{ "avl_res": 5, "res_status": "Unavailable", "code": "CCC" },
{ "avl_res": 3, "res_status": "Unavailable", "code": "DDD" },
];
const results = [];
const findItem = {};
for (const { avl_res, code, res_status } of arr) {
let item = findItem[code];
const res = res_status == 'Available' ? avl_res : 0;
if (item) {
item.total_res += avl_res;
item.avl_res += res;
}
else {
item = { avl_res: res, total_res: avl_res, code };
results.push(item);
findItem[code] = item;
}
}
console.log(results);

Related

How to count values without the duplicate in react

Language used : js with react
I need to count how much "theme" I have but not if he's already count/exist
data example :
movies = [{"id" : 1, "name": "Ps: i love you", "theme": { "id": 1, "name": "love"} },
{"id" : 2, "name": "Holiday", "theme": { "id": 1, "name": "love"} },
{"id" :3, "name": "Scary Movie", "theme": { "id": 2, "name": "horror"} }]
Here, i have two theme : love and horror.
I know how to get the number of theme but i don't want to count the duplicate, so here i only want to get "2" and no "3" .
what i am actually trying :
const movieTheme= movies.filter((item) => item.theme.name);
const movieThemeCount = movieTheme.length;
console.log(movieThemeCount ); // of course i'm here getting 3 instead of 2
There's a bunch of ways to create a unique list of themes. Use map and filter to shape your array however you require it. You should look into the Array.filter method itself, the third parameter self would have helped you a lot here :)
const movies = [
{ id: 1, name: 'Ps: i love you', theme: { id: 1, name: 'love' } },
{ id: 2, name: 'Holiday', theme: { id: 1, name: 'love' } },
{ id: 3, name: 'Scary Movie', theme: { id: 2, name: 'horror' } }
];
const themes = movies
.map((movie) => movie.theme)
.filter((theme, index, self) => self.findIndex((t) => t.id === theme.id) === index);
console.log(themes); // [{"id":1,"name":"love"},{"id":2,"name":"horror"}]
console.log(themes.length); // 2
I edited your code, try this, it is tested
movies = [{"id": 1, "name": "Ps: i love you", "theme": {"id": 1, "name": "love"}},
{"id": 2, "name": "Holiday", "theme": {"id": 1, "name": "love"}},
{"id": 3, "name": "Scary Movie", "theme": {"id": 2, "name": "horror"}}]
const movieTheme = []
movies.forEach((item) => {
let exists = false
for (let i = 0; i < movieTheme.length; i++) {
if (movieTheme[i] === item.theme.name) {
exists = true;
}
}
if (exists) {
return false
} else {
movieTheme.push(item.theme.name)
return item.theme.name;
}
});
const movieThemeCount = movieTheme.length;
console.log(movieTheme);
console.log(movieThemeCount);
I writed what you need inside handleCountTheme function. It just use one loop inside to count the number of theme.
const movies = [{"id" : 1, "name": "Ps: i love you", "theme": { "id": 1, "name": "love"} },
{"id" : 2, "name": "Holiday", "theme": { "id": 1, "name": "love"} },
{"id" :3, "name": "Scary Movie", "theme": { "id": 2, "name": "horror"} }]
const handleCountTheme = (movies) => {
const idList = []
movies.forEach((item) => {
if(idList.includes(item.theme.id)) return;
idList.push(item.theme.id);
})
return idList.length;
}
console.log(handleCountTheme(movies))

Rename keys in reduce function

I am essentially receiving data from another API that takes the following structure
const ob = {
"dataOne": [
{
"type": "Type 1",
"name": "email.failed"
},
{
"type": "Type 1",
"name": "email.success"
},
{
"type": "Type 2",
"name": "email.success"
},
{
"type": "Type 3",
"name": "email.success"
},
],
};
What I was doing what creating a new array which essentially gets each unique type and then does a total count and an individual count of each unique name.
I also have another data set I combine with this but omitted for this question.
The working code I have is
const ob = {
"dataOne": [
{
"type": "Type 1",
"name": "email.failed"
},
{
"type": "Type 1",
"name": "email.success"
},
{
"type": "Type 2",
"name": "email.success"
},
{
"type": "Type 3",
"name": "email.success"
},
],
};
const dataReduced = ob.dataOne.reduce((acc, o) => {
if (!acc[o.type]) {
acc[o.type] = [
{
count: 0,
'email.success': 0,
'email.failed': 0,
},
];
}
acc[o.type][0].count = (acc[o.type][0].count || 0) + 1;
acc[o.type][0][o.name] = acc[o.type][0][o.name] + 1;
return acc;
}, {});
console.log(dataReduced);
What I can't figure out however, because it is matching on email.success is how to rename these in my final output. I essentially want to remove the email. part.
So instead, the console.log should be
{
Type 1: [{
count: 2,
failed: 1,
success: 1
}],
Type 2: [{
count: 1,
failed: 0,
success: 1
}],
Type 3: [{
count: 1,
failed: 0,
success: 1
}]
}
How would I achieve this?
Thanks
You can do something like this
const ob = {
"dataOne": [
{
"type": "Type 1",
"name": "email.failed"
},
{
"type": "Type 1",
"name": "email.success"
},
{
"type": "Type 2",
"name": "email.success"
},
{
"type": "Type 3",
"name": "email.success"
},
],
};
const dataReduced = ob.dataOne.reduce((acc, o) => {
const name = o.name.replace('email.', '')
if (!acc[o.type]) {
acc[o.type] = [
{
count: 0,
'success': 0,
'failed': 0,
},
];
}
acc[o.type][0].count = (acc[o.type][0].count || 0) + 1;
acc[o.type][0][name] = acc[o.type][0][name] + 1;
return acc;
}, {});
console.log(dataReduced);
I've no clue why the console output is actually in your Browser console and not in this JS Constainer, but here, no reduce, but I don't even see the reason why a reduce would be better here:
var arr = [
{
"type": "Type 1",
"name": "email.failed"
},
{
"type": "Type 1",
"name": "email.success"
},
{
"type": "Type 2",
"name": "email.success"
},
{
"type": "Type 3",
"name": "email.success"
},
];
var result = [];
for (var o of arr) {
if (!result.hasOwnProperty(o.type)) {
var newObj = {
count: 1,
failed: 0,
success: 0,
};
if (o.name.indexOf('failed') !== -1) {
newObj.failed++;
}
if (o.name.indexOf('success') !== -1) {
newObj.success++;
}
result[o.type] = [newObj];
} else {
result[o.type][0].count++;
if (o.name.indexOf('failed') !== -1) {
result[o.type][0].failed++;
}
if (o.name.indexOf('success') !== -1) {
result[o.type][0].success++;
}
}
}
console.log(result);
I resolved this using the for in loop:
for(let elem in dataReduced){
dataReduced[elem][0]['success'] = dataReduced[elem][0]['email.success'];
dataReduced[elem][0]['failed'] = dataReduced[elem][0]['email.failed'];
delete dataReduced[elem][0]['email.success'];
delete dataReduced[elem][0]['email.failed'];
}

Object Manipulation javascript

i have a big problem to manipulate a js object. I have this object :
"daily_operator_trend": {
"2018-08-01": {},
"2018-08-02": {},
"2018-07-16": {
"1": 1,
"2": 4,
"3": 3
},
"2018-07-18": {
"1": 1,
"3": 7
}
},
"operatorStats": [
{
"min_response_time": 5,
"max_deepness": 3,
"max_response_time": 5,
"min_deepness": 3,
"details": {
"phoneNumber": "001122333",
"allBots": true,
"surname": "Sky",
"nickname": "jesky",
"name": "Je",
"type": "owner",
"operatorId": 1,
"userId": "834f6de213c7d79bd64031371773b154",
"email": "jesky#hotmail.it",
"maxConversation": -1,
"botIdList": [
"1ec0e59069561da21727e3a56d05ef2d",
"0ddfc38f54f51f7b40e1057436b34a6f",
"37c43963d3e716bc4e41e1e6a32ed7f1"
]
},
"avg_deepness": 3,
"avg_response_time": 5
}]
Where in daily_operator_trend we have a key like a datae and a value is an object, in this object the key is the operator id and value is the num of conversation. I need to manipulate and transform it in a new array of object like this :
series: [ {name:'jesky', data:[0,0,1,1]}]
I'm trying with this code:
let columnDataConv = data.operatorStats.reduce(function(map, obj){
let newObj = [];
let cData = Object.keys(data.daily_operator_trend).reduce(function(m, o){
m['name'] = '';
m['data'] = [];
for (let [key, value] of Object.entries(data.daily_operator_trend[o])){
if (key == obj.details.operatorId){
if ( obj.details.nickname in m){
m['data'].push(value);
}else {
m['name']= obj.details.nickname;
m['data'].push(value);
}
}else {
m['data'].push(0);
}
newObj.push(m);
}
return newObj;
}, {})
map={...cData};
return map;
}, {});
Can you help me ?
const data = {
"daily_operator_trend": {
"2018-08-01": {
"1": 1,
"2": 4,
"3": 3
},
"2018-08-02": {
"1": 10,
"2":15,
"3":25
},
"2018-07-16": {
},
},
"operatorStats": [
{
"min_response_time": 5,
"max_deepness": 3,
"max_response_time": 5,
"min_deepness": 3,
"details": {
"phoneNumber": "001122333",
"allBots": true,
"surname": "Sky",
"nickname": "jesky",
"name": "Je",
"type": "owner",
"operatorId": 1,
"userId": "834f6de213c7d79bd64031371773b154",
"email": "jesky#hotmail.it",
"maxConversation": -1,
"botIdList": [
"1ec0e59069561da21727e3a56d05ef2d",
"0ddfc38f54f51f7b40e1057436b34a6f",
"37c43963d3e716bc4e41e1e6a32ed7f1"
]
},
"avg_deepness": 3,
"avg_response_time": 5
},
{
"min_response_time": 4,
"max_deepness": 2,
"max_response_time": 1,
"min_deepness": 2,
"details": {
"phoneNumber": "001122333",
"allBots": true,
"surname": "SkyWine",
"nickname": "john",
"name": "Jeremy",
"type": "owner",
"operatorId": 2,
"userId": "834f6de213c7d79bd64031371773b155",
"email": "john#hotmail.it",
"maxConversation": -1,
"botIdList": [
"1ec0e59069561da21727e3a56d05ef2d",
"0ddfc38f54f51f7b40e1057436b34a6g",
"37c43963d3e716bc4e41e1e6a32ed7f1"
]
},
"avg_deepness": 3,
"avg_response_time": 5
},
{
"min_response_time": 4,
"max_deepness": 2,
"max_response_time": 1,
"min_deepness": 5,
"details": {
"phoneNumber": "001122333",
"allBots": true,
"surname": "SkyWine",
"nickname": "Frank",
"name": "Jeremy",
"type": "owner",
"operatorId": 3,
"userId": "834f6de213c7d79bd64031371773b156",
"email": "frank#hotmail.it",
"maxConversation": -1,
"botIdList": [
"1ec0e59069561da21727e3a56d05ef2d",
"0ddfc38f54f51f7b40e1057436b34a6f",
"37c43963d3e716bc4e41e1e6a32ed7f2"
]
},
"avg_deepness": 3,
"avg_esponse_time": 5
}
]
};
function mergeNames (arr) {
return _.chain(arr).groupBy('name').mapValues(function (v) {
return _.chain(v).pluck('value').flattenDeep();
}).value();
}
let newObj = [];
let columnDataConv = data.operatorStats.reduce(function(map, obj){
for (let [k,v] of Object.entries(data.daily_operator_trend)){
for (let [key, value] of Object.entries(v)){
let m = {};
let dati = [];
if (key == obj.details.operatorId){
if(newObj.length > 0){
for(let i = 0;i< newObj.length; ++i){
if(newObj[i].name === obj.details.nickname){
dati=[];
dati.push(value);
newObj[i].data.push(...dati);
break;
}else{
dati=[];
m = {};
m['name']= obj.details.nickname;
dati.push(value);
m['data']=dati;
newObj.push(m);
break;
}
};
}else{
dati=[];
m = {};
m['name']= obj.details.nickname;
dati.push(value);
m['data']=dati;
newObj.push(m);
break;
}
}
}
}
map={...newObj};
return map;
}, []);
console.log(columnDataConv);
Now i have the array of objects but only the first entry of my array is correct. Why the other element aren't merged?

Javascript get data totals into list

I have this data:
{
"id": "123",
"name": "name here",
"thsub": {
"637": {
"id": "637",
"name": "Sub 1",
"stats": {
"items": 5,
},
"ons": null
},
"638": {
"id": "638",
"name": "Sub 2",
"stats": {
"items": 10,
},
"ons": null
}
},
"ph": 10,
}
Here's is the code:
mydata = [mydata];
var chList=[];
var thList=[];
var thCount=[];
for (var i = 0; i < mydata.length; i++) {
var obj = mydata[i];
var cl = obj.name;
if (obj.thsub != null) {
chList.push(cl);
}
if(obj.thsub) {
if (i < 10) {
var nme = Object.keys(obj.thsub).map( function(key){
var item = obj.thsub[key];
return item.name;
});
thCount.push(numberofitems);
thList = thList.concat(nme);
thCount = thCount.concat(Array(nme.length).fill(nme.length));
}
}
}
My problem is in the thCount ... what I need to do is to count each "items" on obj.thsub.638 or other ...stats.items and put the totals into thCount like I've got in thList.
So the desired result woule be 5 and 10 in other words: [5, 10] in this case.
thCount would be [5, 10]
How can I do this?
you should access the json objects using key value, index is for arrays. below code just does the thcount for you
var data = {
"id": "123",
"name": "name here",
"thsub": {
"637": {
"id": "637",
"name": "Sub 1",
"stats": {
"items": 5,
},
"ons": null
},
"638": {
"id": "638",
"name": "Sub 2",
"stats": {
"items": 10,
},
"ons": null
}
},
"ph": 10,
};
var thCount = [];
for(key in data.thsub ){
if(data.thsub[key].stats){
thCount.push(data.thsub[key].stats.items);
}
}
console.log(thCount);
Object.values gives you the list of values of a given object and then you can map your result in an array. in ES5:
var arr = Object.values(mydata.thsub).map(function(item) {
return item.stats.items
});
in ES6:
const list = Object.values(mydata.thsub).map(item => item.stats.items);
You could use an iterative recursive approach for getting the wanted values.
function getValues(object, key) {
function iter(o) {
if (key in o) {
result.push(o[key]);
}
Object.keys(o).forEach(function (k) {
if (o[k] && typeof o[k] === 'object') {
iter(o[k]);
}
});
}
var result = [];
iter(object);
return result;
}
var data = { id: "123", name: "name here", thsub: { 637: { id: "637", name: "Sub 1", stats: { items: 5, }, ons: null }, 638: { id: "638", name: "Sub 2", stats: { items: 10, }, ons: null } }, ph: 10, };
console.log(getValues(data, 'items'));
.as-console-wrapper { max-height: 100% !important; top: 0; }

jqTree - creating tree data from json

I'm trying to display a tree using jqTree - http://mbraak.github.com/jqTree
I need help with creating the tree data from JSON.
My JSON data looks like this:
{
"d" : {
"results": [
{
"Title": "Committee A",
"ReportsToId": null,
"Rank": 1,
"Id": 5
},
{
"Title": "Committee B",
"ReportsToId": 5,
"Rank": 2,
"Id": 7
},
{
"Title": "Committee C",
"ReportsToId": 7,
"Rank": 3,
"Id": 13
},
{
"Title": "Committee D",
"ReportsToId": 13,
"Rank": 4,
"Id": 1
},
{
"Title": "Committee E",
"ReportsToId": 13,
"Rank": 4,
"Id": 3
}
]
}
}
I want to end up with this:
var treeData = [
{
label: 'Committee A',
children: [
{
label: 'Committee B',
children: [
{
label: 'Committee C',
children: [
{ label: 'Committee D' },
{ label: 'Committee E' }
]
}]
}
]
}
];
Here's a solution adapted from http://www.jqwidgets.com/populating-jquery-tree-with-json-data/:
var jqTreeData = function (data) {
var source = [];
var items = [];
// build hierarchical source.
for (i = 0; i < data.length; i++) {
var item = data[i];
var title = item["Title"];
var reportsToId = item["ReportsToId"];
var id = item["Id"];
if (items[reportsToId]) {
var item =
{
label: title
};
if (!items[reportsToId].children) {
items[reportsToId].children = [];
}
items[reportsToId].children[items[reportsToId].children.length] = item;
items[id] = item;
}
else {
items[id] =
{
label: title
};
source[0] = items[id];
}
}
return source;
}

Categories

Resources