Get values from multidimensional object to list - javascript

I have object:
data = {
"usa": {
"a": {
"min": 1,
"max": 2,
"avg": 1.5
},
"b": {
"min": 3,
"max": 5,
"avg": 4
}
},
"canada": {
"c": {
"min": 1,
"max": 2,
"avg": 1.5
}
}
}
I would like receive all max values from second dimension, for example:
function getMaxValues(country: string): number[] {
const maxValues: number[] = data[country]???
return maxValues;
}
I any better way than iterate over this object and collect results? In other languages are special functions for this. I don't want use iteration because this object is very large and usually specific functions for this are more efficient.

You can do:
Object.values(data).flatMap((country) => {
return Object.values(country).map(({max}) => max);
});

You need to get the country object values then map to get max value.
let data = {
"usa": {
"a": {
"min": 1,
"max": 2,
"avg": 1.5
},
"b": {
"min": 3,
"max": 5,
"avg": 4
}
},
"canada": {
"c": {
"min": 1,
"max": 2,
"avg": 1.5
}
}
}
function getMaxValues(country) {
const maxValues = Object.values(data[country]).map(v => v.max);
return maxValues;
}
console.log(getMaxValues('usa'));

You can reduce the entries of the object:
const data = {
"usa": {
"a": {
"min": 1,
"max": 2,
"avg": 1.5
},
"b": {
"min": 3,
"max": 5,
"avg": 4
}
},
"canada": {
"c": {
"min": 1,
"max": 2,
"avg": 1.5
}
}
};
const maxValuesPerCountry = Object.entries(data)
.reduce( (acc, [key, value]) =>
( {...acc, [key]: Object.entries(value).map(([, v]) => v.max) } ), {} );
console.log(maxValuesPerCountry);
console.log(`usa: ${maxValuesPerCountry.usa}`);
.as-console-wrapper {
max-height: 100% !important;
}

Related

Appending last JSON object to the previous in array

I have a function that is outputting an array of json objects, where the last one is unique in structure:
// multi
[
{ "min": 10, "max": 200, "sum": 580, "avg": 72.5 },
{ "min": 10, "max": 470, "sum": 8300, "avg": 103.75 },
{ "largest": 470 }
]
// single
[
{ "min": 20, "max": 190, "sum": 270, "avg": 90 },
{ "largest": 190 }
]
Is it possible to have it append the last part { "largest": n } to the other objects in the array?
So the output would be:
// multi
[ { "min": 10, "max": 200, "sum": 580, "avg": 72.5, "largest": 470 },
{ "min": 10, "max": 470, "sum": 8300, "avg": 103.75, "largest": 470 }
]
// single
[
{ "min": 20, "max": 190, "sum": 270, "avg": 90, "largest": 190 }
]
Here is a link to the snippet of code that outputs the above.
Slice the array to omit the last entry, then map each entry to merge in the last entry
function mergeLastEntry(arr) {
const last = arr[arr.length - 1] // get the last entry
// map each object (except the last) to merge in the `last` object
return arr.slice(0, -1).map(o => ({ ...o, ...last }))
}
const multi =[{"min":10,"max":200,"sum":580,"avg":72.5},{"min":10,"max":470,"sum":8300,"avg":103.75},{"largest":470}]
const single = [{"min":20,"max":190,"sum":270,"avg":90},{"largest":190}]
console.log("multi", mergeLastEntry(multi))
console.log("single", mergeLastEntry(single))
.as-console-wrapper { max-height: 100% !important; }

Group an array of objects based on a specific field

I have an array of objects. I want to group them by a specific field.
[
{
"name": "JOHN",
"type": 1,
"sum": 5
},
{
"name": "SERA",
"type": 1,
"sum": 43
},
{
"name": "SERA",
"type": 2,
"sum": 129
},
{
"name": "JOHN",
"type": 2,
"sum": 200
}
]
The output I expect for grouping by name attribute is as follows.
{
// Group #1
"JOHN": [
{
"type": 2,
"sum": 200
}
{
"type": 1,
"sum": 5
}
],
// Group #2
"SERA":[
{
"type": 1,
"sum": 43
},
{
"type": 2,
"sum": 129
},
]
}
I used nested loops, but unfortunately the execution speed was slow and it did not give the right results.
As if you mentioned, we can use an object instead of an array for the most outer wrapper. And also swap inside one object to an array, then this is a possible solution.
var data = [{"name": "JOHN","type": 1,"sum": 5},{"name": "SERA","type": 1,"sum": 43},{"name": "SERA","type": 2,"sum": 129},{"name": "JOHN","type": 2,"sum": 200}];
var newData = {};
data.forEach( (item) => {
if (!(item['name'] in newData)) {
newData[item['name']] = [];
}
newData[item['name']].push(
{
'type': item['type'],
'sum' : item['sum']
}
);
});
console.log(newData);
Your proposed output structure is not valid, however using Array.reduce you can create an object in which all the properties are arrays of objects:
const data = [
{
"name": "JOHN",
"type": 1,
"sum": 5
},
{
"name": "SERA",
"type": 1,
"sum": 43
},
{
"name": "SERA",
"type": 2,
"sum": 129
},
{
"name": "JOHN",
"type": 2,
"sum": 200
}
];
const result = data.reduce((c, {name, type, sum}) => {
c[name] = c[name] || [];
c[name].push({type, sum});
return c;
}, {});
console.log(result);
One more way with forEach, destructuring and ?? operator
const merge = (arr) => {
const obj = {};
arr.forEach(({ name, ...rest }) => (obj[name] ??= []).push(rest));
return obj;
};
const data = [
{
name: "JOHN",
type: 1,
sum: 5,
},
{
name: "SERA",
type: 1,
sum: 43,
},
{
name: "SERA",
type: 2,
sum: 129,
},
{
name: "JOHN",
type: 2,
sum: 200,
},
];
console.log(merge(data));
You can use this function which take advantage of Array.prototype.reduce to transform the initial data to another structure of array.
let data = [
{
"name": "JOHN",
"type": 1,
"sum": 5
},
{
"name": "SERA",
"type": 1,
"sum": 43
},
{
"name": "SERA",
"type": 2,
"sum": 129
},
{
"name": "JOHN",
"type": 2,
"sum": 200
}
];
function groupedBy(data, field) {
let fieldValues = [...data].reduce((acc, current) => {
return acc.concat(current[field]);
}, []).filter((value, index, self) => {
return self.indexOf(value) === index;
});
let results = fieldValues.reduce((acc, item) => {
let items = [...data].filter(el => {
return el.name === item;
});
items.forEach(i => delete i.name);
return Object.assign(acc, { [item]: items});
}, {});
return results;
}
console.log(groupedBy(data, "name"));

How to get the array of objects based on condition

How to get the array of objects based on condition in javascript.
I have array object obj in which each objects w1,w2...wn should have count greater than 2.
How to filter the array object based on object key in javascript.
function getObject (obj1){
var result = obj1.filter(e=> e.w1.count > 2 && e.w2.count > 2);
return result;
}
var output = this.getObject(obj1);
var obj1=[
{
"memberid": "s1",
"w1":{"count": 1, "qty": 1},
"w2":{"count": 0, "qty": 0},
... wn
"totalcount": 1
},
{
"memberid": "s2",
"w1":{"count": 2, "qty": 2, "amount": 400.0},
"w2":{"count": 1, "qty": 2, "amount": 503.0},
... wn
"totalcount": 5
},
{
"memberid": "s3",
"w1":{"count": 3, "qty": 2, "amount": 0.0},
"w2":{"count": 3, "qty": 4, "amount": 503.0},
... wn
"totalcount": 6
}
]
Expected Output:
[
{
"memberid": "s3",
"w1":{"count": 3, "qty": 2, "amount": 0.0},
"w2":{"count": 3, "qty": 4, "amount": 503.0},
... wn
"totalcount": 6
}
]
You can filter your array based on every value in each object either not being an object, or if it is an object, having a count greater than 2:
const obj1 = [{
"memberid": "s1",
"w1": {
"count": 1,
"qty": 1
},
"w2": {
"count": 0,
"qty": 0
},
"totalcount": 1
},
{
"memberid": "s2",
"w1": {
"count": 2,
"qty": 2,
"amount": 400.0
},
"w2": {
"count": 1,
"qty": 2,
"amount": 503.0
},
"totalcount": 5
},
{
"memberid": "s3",
"w1": {
"count": 3,
"qty": 2,
"amount": 0.0
},
"w2": {
"count": 3,
"qty": 4,
"amount": 503.0
},
"totalcount": 6
}
];
const out = obj1.filter(o => Object.values(o).every(v => typeof v != 'object' || v.count > 2));
console.log(out);
you need to iterate over the object keys, filtering out the invalid ones
function getObject(obj1) {
// filter
return obj1.filter(e =>
// based on the entries [key, value]
Object.entries(e)
// filter out entries where key is not a w followed by a number
.filter(val => val[0].match(/w\d+/))
// if every selected entry as a count > 2
.every(val => val[1].count > 2)
);
}
const obj1=[{memberid:"s1",w1:{count:1,qty:1},w2:{count:0,qty:0},totalcount:1},{memberid:"s2",w1:{count:2,qty:2,amount:400},w2:{count:1,qty:2,amount:503},totalcount:5},{memberid:"s3",w1:{count:3,qty:2,amount:0},w2:{count:3,qty:4,amount:503},totalcount:6}];
const output = this.getObject(obj1);
console.log(output)
docs of usefull functions :
Object.entries,
Array.filter,
Array.every
function getObject (obj1) {
var result = obj1.filter((e) => {
var isValid = false;
var i = 1;
while (e['w' + i]) {
if (e['w' + i].count > 2) {
isValid = true;
} else {
isValid = false;
break;
}
i++;
}
return isValid;
});
return result;
}

Converting one data structure to another

Hi I need to parse some structure to to show some data in line chart. I have this data structure , and I need to convert it for array example_output:
data = {
"el1": [{
"date": "2017.01",
"data1": {
"series_1": {
"a": 10,
"b": 20,
"c": 50,
"d": 15,
"e": 8
},
"Series_2": {
"yes": 5,
"no": 3
},
"Series_3": {
"s": 2,
"n": 9
}
},
"text": [{
"t": "header",
"c": "text"
}, {
"t": "header2",
"c": "text2"
}]
}, {
"date": "2017.02",
"data1": {
"series_1": {
"a": 56,
"b": 23,
"c": 45,
"d": 69,
"e": 14
},
"Series_2": {
"yes": 2,
"no": 1
},
"Series_3": {
"s": 6,
"n": 4
}
},
"text": [{
"t": "header",
"c": "text"
}, {
"t": "header2",
"c": "text2"
}]
}, {
"date": "2017.03",
"data1": {
"series_1": {
"a": 15,
"b": 12,
"c": 10,
"d": 54,
"e": 4
},
"Series_2": {
"yes": 20,
"no": 16
},
"Series_3": {
"s": 9,
"n": 7
}
},
"text": [{
"t": "header",
"c": "text"
}, {
"t": "header2",
"c": "text2"
}]
}
]
};
and I need OUTPUT like this for chartist.js
var example_output = [{
labels: ['2017.01', '2017.02', '2017.03'],
series: {
[10, 56, 15],
[20, 23, 12],
[50, 45, 10],
[15, 69, 54],
[8, 14, 4]
},
labels: ['2017.01', '2017.02', '2017.03'],
series: {
[5, 2, 20],
[3, 1, 16]
},
labels: ['2017.01', '2017.02', '2017.03'],
series: {
[2, 6, 9],
[9, 4, 7]
},}] ;
Please compare digits from the original and the example_output to better understand how this should look like. I use code for parse this but someting goes wrong:
function parseData(data) {
var _newData = {};
var allSeries = [];
data.elements.forEach(function(el){
_newData[el.date] = el.info
if(allSeries.length==0)
allSeries = Object.keys(el.info);
});
return allSeries.map(function(el) {
var obj = {
labels: [],
series: []
};
obj.labels = Object.keys(_newData);
Object.keys(_newData).forEach(function(_el) {
obj.series.push(Object.values(_newData[_el][el]));
});
var _newSeries = [];
obj.series[0].forEach(function(el, i){
_newSeries.push([el, obj.series[1][i]]);
});
obj.series = _newSeries;
return obj;
});
}
You can use array#forEach and array#reduce. Use first loop to iterate through el1 and then use reduce for the series key and accumulate the result in the output_example.
NOTE: The series in your output is incorrect. It should be an array instead of object.
const data = {"el1": [{"date": "2017.01","data1": {"series_1": {"a": 10,"b": 20,"c": 50,"d": 15,"e": 8},"Series_2": {"yes": 5,"no": 3},"Series_3": {"s": 2,"n": 9}},"text": [{"t": "header","c": "text"}, {"t": "header2","c": "text2"}]}, {"date": "2017.02","data1": {"series_1": {"a": 56,"b": 23,"c": 45,"d": 69,"e": 14},"Series_2": {"yes": 2,"no": 1},"Series_3": { "s": 6,"n": 4 }},"text": [{"t": "header","c": "text"}, {"t": "header2","c": "text2"}]}, {"date": "2017.03","data1": {"series_1": {"a": 15,"b": 12,"c": 10,"d": 54,"e": 4},"Series_2": {"yes": 20, "no": 16},"Series_3": {"s": 9, "n": 7}},"text": [{"t": "header","c": "text"}, {"t": "header2","c": "text2" }]}]};
transpose = (arr) => arr.reduce((r,v,i) => {
(r[i] = r[i] || []).push(v);
return r;
},[]);
let example_output = [];
data.el1.forEach((o) => {
Object.keys(o.data1).reduce((r, k, i) => {
r[i] = r[i] || {};
if('labels' in r[i])
r[i]['labels'].push(o.date);
else
r[i]['labels'] = [o.date];
if('series' in r[i])
Object.values(o.data1[k]).forEach((v,j) => r[i]['series'][j].push(v));
else
r[i]['series'] = transpose(Object.values(o.data1[k]));
return r;
},example_output);
},[]);
console.log(example_output);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Multiply the object properties

someone tell me how to multiply object's properties? I need this object multiplied by the count of property price and put together
var menu = [
{
"id": 5,
"price": 13,
"count": 2
},
{
"id": 8,
"price": 7,
"count": 3
},
{
"id": 9,
"price": 17,
"count": 1
}
]
var sum = 0;
for (var key in menu) {
for (var key1 in menu[key]) {
//console.log(key1);
if (key1 == 'price'){
price += menu[key][key1];
}
}
}
but I have no idea how to multiply count property
You can use Array.prototype.map with Array.prototype.reduce.
.map takes a callback function which will multiply the price of each item by the count and creates a new array looking like this:
[26,21,17].
.reduce takes a callback as well, iterating over the new create array summing up the multiplied prices resulting to:
64
let menu = [
{
"id": 5,
"price": 13,
"count": 2
},
{
"id": 8,
"price": 7,
"count": 3
},
{
"id": 9,
"price": 17,
"count": 1
}
]
let sum = menu.map(p => p.price * p.count).reduce((a,b) => a + b)
console.log("Total:",sum)
You probably want something like this:
{
"id": 5,
"price": 13,
"count": 3,
"value": function() {return this.price * this.count;}
}
You can do that by either making an object and adding a prototype (which saves memory and time) or construct it that way each time.
Otherwise you can just do:
var obj = { ... } // your stuff
alert(obj.price * obj.count)
suppose you want to calculate the sum
var menu = [
{
"id": 5, "price": 13, "count": 2 }, {
"id": 8, "price": 7, "count": 3 }, { "id": 9, "price": 17, "count": 1 } ];
var sum = 0, item;
for(item in menu)
{
sum += menu[item].price * menu[item].count;
}
console.log(sum);

Categories