Let's assume we have the following data entries:
const data = [{
"id": "0",
"name": {
"first": "",
"last": ""
},
"nickname": "test",
"rating": {
"kw": 1,
"dc": 2,
"imp": 3,
"pat": 4
}
},
{
"id": "1",
"name": {
"first": "",
"last": ""
},
"nickname": "test2",
"rating": {
"kw": 28,
"dc": 26,
"imp": 27,
"pat": 14
}
},
{
"id": "2",
"name": {
"first": "",
"last": ""
},
"nickname": "test3",
"rating": {
"kw": 11,
"dc": 8,
"imp": 9,
"pat": 1
}
}
];
I don't know these object keys within rating, so the object could also look like:
{
"id": "1",
"name": {
"first": "",
"last": ""
},
"nickname": "test2",
"rating": {
"ab": 28,
"cd": 26,
"moep": 27,
"bla": 14
}
}
I would like to do the following:
Generate a new object based on the data object keys dynamically (as I don't know them)
Create a subobject {min: xx, max: xx} for all those object keys
So the result should look like this:
{
kw: {
min: 1,
max: 28
},
dc: {
min: 2,
max: 26
},
imp: {
min: 3,
max: 27
},
pat: {
min: 1,
max: 14
},
}
How can I achieve this ?
You can reduce the array, and use Array.forEach() to iterate the entries, and create/populate the min and max values of each rating key:
const data=[{id:"0",name:{first:"",last:""},nickname:"test",rating:{kw:1,dc:2,imp:3,pat:4}},{id:"1",name:{first:"",last:""},nickname:"test2",rating:{kw:28,dc:26,imp:27,pat:14}},{id:"2",name:{first:"",last:""},nickname:"test3",rating:{kw:11,dc:8,imp:9,pat:1}}];
const result = data.reduce((r, { rating }) => {
Object.entries(rating).forEach(([k, v]) => {
if(!r[k]) r[k] = { min: v, max: v }; // if doesn't exist min = max = current value
else if(v < r[k].min) r[k].min = v; // if current value is less than min -> min = current value
else if(v > r[k].max) r[k].max = v; // if current value is more than max -> max = current value
});
return r;
}, {});
console.log(result);
You could reduce the array. Loop through the keys of rating and set the min and max for each key
const data=[{id:"0",name:{first:"",last:""},nickname:"test",rating:{kw:1,dc:2,imp:3,pat:4}},{id:"1",name:{first:"",last:""},nickname:"test2",rating:{kw:28,dc:26,imp:27,pat:14}},{id:"2",name:{first:"",last:""},nickname:"test3",rating:{kw:11,dc:8,imp:9,pat:1}}];
const output = data.reduce((acc, { rating }) => {
for (const key in rating) {
const value = rating[key];
acc[key] = acc[key] || { min: value, max: value }; // if key doesn't exist, add it
acc[key].min = Math.min( acc[key].min, value )
acc[key].max = Math.max( acc[key].max, value )
}
return acc;
}, {})
console.log(output)
Related
I want to simplify and get last part missing.
So, I have an array of objects like:
const data = [{
"company": "aaa",
"qty": 1,
"id": 1
}, {
"company": "bbb",
"qty": 14,
"id": 2
}, {
"company": "ccc",
"qty": 2,
"id": 3
}, {
"company": "ddd",
"qty": 5,
"id": 4
},
{
"company": "eee",
"qty": 55,
"id": 5
}
];
I need to add the percentage based on qty and overall create a new object with detail of only companies with percentage greater than "X" (let's say 10) and others merged in a "other companies", like a similar
{
"idCompany": 2,
"name": "bbb",
"percentage": 18.181818181818183,
"qty": 14
},{
"idCompany": 5,
"name": "eee",
"percentage": 71.42857142857143,
"qty": 55
},{
"idCompany": null,
"name": "others",
"percentage": 10.391 // 100 - 71.42xxx - 18.18
"qty": 8 // 1 + 2 + 5
},
So, my steps:
Get the total:
const total = data.reduce((i, el) => i+el.qty, 0);
Add the percentage to start object:
let rawData = data.map(el => {
return {
name: el.company,
qty: el.qty,
idCompany: el.id,
percentage: (el.qty/total)*100,
}
})
Get only companies with percentage greater than X (e.g. 10)
let consolidateCompanies = rawData.filter(el => el.percentage > 10);
But...
Now, how can I get the OTHERS companies and add to the consolidateCompanies object? And with a more beautiful code?
const data = [{
"company": "aaa",
"qty": 1,
"id": 1
}, {
"company": "bbb",
"qty": 14,
"id": 2
}, {
"company": "ccc",
"qty": 2,
"id": 3
}, {
"company": "ddd",
"qty": 5,
"id": 4
},
{
"company": "eee",
"qty": 55,
"id": 5
}
];
// Get the total
const total = data.reduce((i, el) => i+el.qty, 0);
// Add percentage to the objects
let rawData = data.map(el => {
return {
name: el.company,
qty: el.qty,
idCompany: el.id,
percentage: (el.qty/total)*100,
}
})
// Get only companies that have percentage greater than 10
let consolidateCompanies = rawData.filter(el => el.percentage > 10);
console.log(consolidateCompanies);
// But I'm missing 1, 3 and 4
You could do this with a couple of Array.reduce() calls.
We'd group companies either by name or 'others', adding percentage and quantity for the others.
const data = [{ "company": "aaa", "qty": 1, "id": 1 }, { "company": "bbb", "qty": 14, "id": 2 }, { "company": "ccc", "qty": 2, "id": 3 }, { "company": "ddd", "qty": 5, "id": 4 }, { "company": "eee", "qty": 55, "id": 5 } ];
const total = data.reduce((i, el) => i+el.qty, 0);
const minPercentage = 10;
const consolidateCompanies = Object.values(data.reduce((acc, el) => {
const percentage = (el.qty/total)*100;
const name = (percentage >= minPercentage) ? el.company: 'others';
const id = (percentage >= minPercentage) ? el.id: null;
acc[name] = acc[name] || { name, percentage: 0, qty: 0, id };
acc[name].percentage += percentage;
acc[name].qty += el.qty;
return acc;
}, {}))
console.log(consolidateCompanies);
.as-console-wrapper { max-height: 100% !important; }
You could seperate others and add only if necessary without grouping by usining another object.
const
data = [{ company: "aaa", qty: 1, id: 1 }, { company: "bbb", qty: 14, id: 2 }, { company: "ccc", qty: 2, id: 3 }, { company: "ddd", qty: 5, id: 4 }, { company: "eee", qty: 55, id: 5 }],
totalQty = data.reduce((t, { qty }) => t + qty, 0),
others = { idCompany: null, name: "others", percentage: 0, qty: 0 },
result = data.reduce((r, { company: name, qty, id: idCompany }) => {
const percentage = qty * 100 / totalQty;
if (percentage >= 10) {
r.push({ idCompany, name, percentage, qty });
} else {
others.qty += qty;
others.percentage = others.qty * 100 / totalQty;
}
return r;
}, []);
if (others.qty) result.push(others);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
here is the refactor of your code
const data = [{
"company": "aaa",
"qty": 1,
"id": 1
}, {
"company": "bbb",
"qty": 14,
"id": 2
}, {
"company": "ccc",
"qty": 2,
"id": 3
}, {
"company": "ddd",
"qty": 5,
"id": 4
},
{
"company": "eee",
"qty": 55,
"id": 5
}
];
const total = data.reduce((i, el) => i+el.qty, 0)
const startWith = [{
"idCompany": null,
"name": "others",
"percentage": 0,
"qty": 0
}]
let rawData = data.reduce((acc, value) => {
// console.log('value', value)
const withPercentage = {
name: value.company,
qty: value.qty,
idCompany: value.id,
percentage: (value.qty/total)*100,
}
if (withPercentage.percentage > 10) {
acc.push(withPercentage)
} else {
acc[0].qty += withPercentage.qty;
acc[0].percentage += withPercentage.percentage;
}
return acc;
}, startWith).filter(f => f.percentage !== 0 && f.qty !== 0);
console.log(rawData)
Use forEach instead of map and filter, and loop the Object with your required need as follows.
const minPerc =10;
const data = [{
"company": "aaa",
"qty": 1,
"id": 1
}, {
"company": "bbb",
"qty": 14,
"id": 2
}, {
"company": "ccc",
"qty": 2,
"id": 3
}, {
"company": "ddd",
"qty": 5,
"id": 4
},
{
"company": "eee",
"qty": 55,
"id": 5
}
];
// Get the total
const total = data.reduce((i, el) => i+el.qty, 0);
let consolidateCompanies = [];
let otherObj={"idCompany": null,
"name": "others",
"percentage": 0,
"qty": 0};
data.forEach(ele=>{
let perc=(ele.qty/total)*100;
if(perc>minPerc){
consolidateCompanies.push({...ele,...{percentage:perc}})
}else{
otherObj.qty +=ele.qty; otherObj.percentage+=perc
} });
consolidateCompanies.push(otherObj);
console.log(consolidateCompanies);
I have an array which is like this:
var arr = [{
"date": "JAN",
"value": 5,
"weight": 3
}, {
"date": "JAN",
"value": 4,
"weight": 23
}, {
"date": "FEB",
"value": 9,
"weight": 1
}, {
"date": "FEB",
"value": 10,
"weight": 30
}]
I want to match the primary key which is heredate. Matching this I want to merge the rest of the key values and get this following output:
[{
"date": "JAN",
"value": [5, 4],
"weight": [3, 23]
}, {
"date": "FEB",
"value": [9, 10],
"weight": [1, 30]
}]
I have written a function like this but can't figure out how to concat the key values:
var arr = [{
"date": "JAN",
"value": 5,
"weight": 3
}, {
"date": "JAN",
"value": 4,
"weight": 23
}, {
"date": "FEB",
"value": 9,
"weight": 1
}, {
"date": "FEB",
"value": 10,
"weight": 30
}]
const transform = (arr, primaryKey) => {
var newValue = [];
for (let i = 0; i < arr.length; i++) {
for (let j = 1; j < arr.length; j++) {
if (primaryKey[i] === primaryKey[j]) {
newValue.push({
...arr[i],
...arr[j]
});
}
}
}
return newValue
};
console.log(transform(arr,'date'))
Using Array#reduce, iterate over the list while updating a Map where the key is the primary-key and the value is the grouped object. In every iteration, create/update the pair.
Using Map#values, return the list of grouped objects
const transform = (arr, primaryKey) => [...
arr.reduce((map, { [primaryKey]: key, ...e }) => {
const { [primaryKey]: k, ...props } = map.get(key) ?? {};
for(let prop in e) {
props[prop] = [...(props[prop] ?? []), e[prop]];
}
map.set(key, { [primaryKey]: key, ...props });
return map;
}, new Map)
.values()
];
const arr = [ { "date": "JAN", "value": 5, "weight": 3 }, { "date": "JAN", "value": 4, "weight": 23 }, { "date": "FEB", "value": 9, "weight": 1 }, { "date": "FEB", "value": 10, "weight": 30 } ];
console.log( transform(arr, 'date') );
The following code should work:
const transform = (arr, primaryKey) => {
var newValue = [];
for(let i = 0; i < arr.length; i++){
arr[i]["value"] = [arr[i]["value"]];
arr[i]["weight"] = [arr[i]["weight"]];
}
newValue.push(arr[0])
for(let i = 1; i < arr.length; i++){
let contains = false;
for(let j = 0; j < newValue.length; j++){
if(newValue[j][primaryKey] == arr[i][primaryKey]){
newValue[j]["value"].push(arr[i]["value"][0]);
newValue[j]["weight"].push(arr[i]["weight"][0]);
contains = true;
}
}
if(!contains){
newValue.push(arr[i]);
}
}
return newValue
};
var arr = [{
"date": "JAN",
"value": 5,
"weight": 3
}, {
"date": "JAN",
"value": 4,
"weight": 23
}, {
"date": "FEB",
"value": 9,
"weight": 1
}, {
"date": "FEB",
"value": 10,
"weight": 30
}]
var newthing = transform(arr,"date");
console.log(newthing);
Output:
[ { date: 'JAN', value: [ 5, 4 ], weight: [ 3, 23 ] },
{ date: 'FEB', value: [ 9, 10 ], weight: [ 1, 30 ] } ]
The way this code works is that first, we turn the values of the keys for "value" and "weight" into lists.
Then, we begin by pushing the first element of arr into newValue.
From here, we do a nested for loop to iterate through the remaining of arr and newValue:
If the value of "date" for every element of arr already exists in newValue, then we will push in the values of "value" and "weight" that belongs to arr.
However, if it does not exist, then we will simply push that element inside of newValue.
I hope this helped answer your question! Pleas let me know if you need any further help or clarification :)
Combining a couple of reduce can also do the same job:
const arr = [{
"date": "JAN",
"value": 5,
"weight": 3
}, {
"date": "JAN",
"value": 4,
"weight": 23
}, {
"date": "FEB",
"value": 9,
"weight": 1
}, {
"date": "FEB",
"value": 10,
"weight": 30
}]
const arrayMappedByDate = arr.reduce((acc, curData) => {
if (acc[curData.date]) {
acc[curData.date].push(curData)
} else {
acc[curData.date] = [curData]
}
return acc
}, {})
const transformedArray = Object.entries(arrayMappedByDate).map(([dateInit, data]) => {
const normalized = data.reduce((acc, cur) => {
if (acc.date) {
acc.value.push(cur.value)
acc.weight.push(cur.weight)
} else {
acc = {
date: cur.date,
value: [cur.value],
weight: [cur.weight]
}
}
return acc
}, {})
return { [dateInit]: normalized }
})
console.log(transformedArray)
I've checked out all available answers regarding nested objects but none helped so far.
I do have a deep nested object like:
let datastat =
{
"statisticData": {
"lastStatisticOne": {
"min": 0,
"max": 10
},
"lastStatisticTwo": {
"min": 0,
"max": 20
},
"firstStatisticOne": {
"min": 0,
"max": 30,
},
"firstStatisticTwo": {
"min": 0,
"max": 40,
},
},
"statisticValue": [
none important Data
]
}
What I try to achieve is:
statisticNew =
[
{
"lastStatisticOne": [{ "name": "min", "value": 0 }, { "name": "max", "value": 10 }]
},
{
"lastStatisticTwo": [{ "name": "min", "value": 0 }, { "name": "max", "value": 20 }]
},
{
"firstStatisticOne": [{ "name": "min", "value": 0 }, { "name": "max", "value": 30 }]
},
{
"firstStatisticTwo": [{ "name": "min", "value": 0 }, { "name": "max", "value": 40 }]
}
]
My attempt failed:
const statistic = [];
statistic.push(datastat.statisticData);
for(let item in statistic){
if (statistic.hasOwnProperty(item)) {
const result = Object.keys(statistic[0]).map(e => ({name: e, value: statistic[0][e]}));
console.log(result);
}
}
How can I achieve the correct output?
This should do it:
let datastat = {
"statisticData": {
"lastStatisticOne": {
"min": 0,
"max": 10
},
"lastStatisticTwo": {
"min": 0,
"max": 20
},
"firstStatisticOne": {
"min": 0,
"max": 30,
},
"firstStatisticTwo": {
"min": 0,
"max": 40,
},
}
}
let newStat = Object.keys(datastat.statisticData).reduce((acc, key) => {
let vals = Object.entries(datastat.statisticData[key]).map(([key, val]) => ({
name: key,
value: val
}))
acc.push({
[key]: vals
});
return acc;
}, []);
You can iterate over the keys of your dataStat and get your expected output like below :
let statisticNew = [];
Object.keys(datastat['statisticData']).map(function (item) {
let stat_obj = {};
let temp_arr = [];
let inner_dict = datastat['statisticData'][item];
Object.keys(inner_dict).map(function (inner_item) {
let temp_obj = {};
temp_obj['name'] = inner_item;
temp_obj['value'] = inner_dict[inner_item];
temp_arr.push(temp_obj)
});
stat_obj[item] = temp_arr;
statisticNew.push(stat_obj);
});
console.log(statisticNew)
This is the Solution provided by Chris G and works perfekt. Thank you!
const statisticNew = Object.entries(datastat.statisticData).map(([key, val]) => ({
[key]: Object.entries(val).map(([name, value]) => ({ name, value }))
}));
You can first reduce value using reduce function and then mapping it accordingly. Here is how:
var datastat = { "statisticData": { "lastStatisticOne": { "min": 0, "max": 10 }, "lastStatisticTwo": { "min": 0, "max": 20 }, "firstStatisticOne": { "min": 0, "max": 30, }, "firstStatisticTwo": { "min": 0, "max": 40, }, }, "statisticValue": []};
reducedValue = Object.entries(datastat.statisticData).reduce((acc, [key, value])=>{
acc[key] = acc[key] || [];
for(const [k, v] of Object.entries(value)){
acc[key].push({name : k, value :v})
}
return acc;
},{});
var result = Object.entries(reducedValue).map(([k,v])=>({[k]:v}));
console.log(result)
I have an array of objects like below:
[
{
"id": 100,
"Name": "T1",
"amt": 15,
},
{
"id": 102,
"Name": "T3",
"amt": 15,
},
{
"id": 100,
"Name": "T1",
"amt": 20,
},
{
"id": 105,
"Name": "T6",
"amt": 15,
}
]
I want to filter the objects in the array by the minimum of amt. There are two objects with id's 100 but different amt (15 and 20). I want to filter the minimum value which is 15. The output should be:
[
{
"id": 100,
"Name": "T1",
"amt": 15,
},
{
"id": 102,
"Name": "T3",
"amt": 15,
},
{
"id": 105,
"Name": "T6",
"amt": 15,
}
]
I followed this post but does not fit with my problem.
Is there any simpler way of doing this, either pure JavaScript or lodash?
You could group by id and take from every group the object with min value of amt.
var data = [{ id: 100, Name: "T1", amt: 15 }, { id: 102, Name: "T3", amt: 15 }, { id: 100, Name: "T1", amt: 20 }, { id: 105, Name: "T6", amt: 15 }],
result = _(data)
.groupBy('id')
.map(group => _.minBy(group, 'amt'))
.value();
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
Use the standard algorithm for finding min value and apply the approach to the reduce function. When you find the min or the equal value to the min, add the current object to the array.
const arr = [{
"id": 100,
"Name": "T1",
"amt": 15,
},
{
"id": 102,
"Name": "T3",
"amt": 15,
},
{
"id": 100,
"Name": "T1",
"amt": 20,
},
{
"id": 105,
"Name": "T6",
"amt": 15,
}
]
const minArr = arr.reduce((acc, curr) => curr.amt <= acc.min ? {
...acc,
min: curr.amt,
arr: [...acc.arr, curr]
} : acc, {
min: Infinity,
arr: []
}).arr
console.log(minArr);
You can do this using a for loop like so:
var minimum = 5;
for(var i = 0; i < yourArray; i++) {
if(yourArray[i].amt < minimum) {
console.log("The " + i + " item in the array's amount is less than the minimum: " + minimum);
}
}
Or you can use Array.filter:
var minimum = 5;
function isBigEnough(value) {
return value >= minimum
}
someArray.filter(isBigEnough)
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?