how to bundle objects in an array by date attribute - javascript

I have a big array with data. Here is a example of the structure:
let data = [
{
date: '2018-11-22',
values: {
a: 10,
b: 20,
c: 5,
},
},
{
date: '2018-11-17',
values: {
a: 5,
b: 10,
c: 15,
},
},
{
date: '2018-06-29',
values: {
a: 10,
b: 30,
c: 10,
},
},
{
date: '2017-12-20',
values: {
a: 30,
b: 40,
c: 5,
},
},
];
I need this data structured in a new array by month and year. The value attributes should be summed up for each month.
So the new array for the example should look like this:
let sortedData = [
{
date: '2018-11',
values: {
a: 15,
b: 30,
c: 20,
},
},
{
date: '2018-06',
values: {
a: 10,
b: 30,
c: 10,
},
},
{
date: '2017-12',
values: {
a: 30,
b: 40,
c: 5,
},
},
];
I'm trying for hours to write a working function but I can't handle it.
Any ideas how I can bundle an array like this?
Thanks for your help!

You can use Array.reduce for this
let data = [ { date: '2018-11-22', values: { a: 10, b: 20, c: 5, }, }, { date: '2018-11-17', values: { a: 5, b: 10, c: 15, }, }, { date: '2018-06-29', values: { a: 10, b: 30, c: 10, }, }, { date: '2017-12-20', values: { a: 30, b: 40, c: 5, }, },];
let res = data.reduce((o, {date, values}) => {
let k = date.slice(0, 7)
o[k] = o[k] || {date: k, values: {a: 0, b: 0, c:0}}
o[k].values.a += values.a
o[k].values.b += values.b
o[k].values.c += values.c
return o
}, {})
console.log(Object.values(res))

You can also do make it more concise and not deal with the individual values props like this:
let data = [{ date: '2018-11-22', values: { a: 10, b: 20, c: 5, }, }, { date: '2018-11-17', values: { a: 5, b: 10, c: 15, }, }, { date: '2018-06-29', values: { a: 10, b: 30, c: 10, }, }, { date: '2017-12-20', values: { a: 30, b: 40, c: 5, }, }, ];
const result = data.reduce((r, {date, values}) => {
date = date.substr(0,7)
r[date] = r[date]
? (Object.keys(values).forEach(k => r[date].values[k] += values[k]), r[date])
: {date, values}
return r
}, {})
console.log(Object.values(result))
This way you would not care if there are 3 of 10 properties in values and you get more generic solution.

Related

How to reassign values in a js object based on the values present in an object within the same object?

I have an array of objects in the following form-
let result = [
{
a: 1,
b: 2,
c: 3,
newValues: {
a: 10,
b: 20,
c: 30
}
},
{
d: 4,
e: 5,
f: 6,
newValues: {
d: 40,
e: 50,
f: 60
}
}
]
And want to convert it to following format -
let result = [
{
a: 10,
b: 20,
c: 30,
},
{
d: 40,
e: 50,
f: 60
}
]
But have been unable to do so.
Any help for converting the older array to the new one will be very much appreciated.
A simple map will do it
let result = [
{
a: 1,
b: 2,
c: 3,
newValues: {
a: 10,
b: 20,
c: 30
}
},
{
d: 4,
e: 5,
f: 6,
newValues: {
d: 40,
e: 50,
f: 60
}
}
]
let data = result.map( r => r.newValues)
console.log(data)
The problem by mapping only the r.newValues is you can potentially lost data that never changed and are not in newValues.
const result = [
{
a: 1,
b: 2,
c: 3,
newValues: {
a: 10,
b: 20,
c: 30
}
},
{
d: 4,
e: 5,
f: 6,
newValues: {
d: 40,
e: 50
}
}
];
const updates = result.map(element => {
const {newValues, rest} = element;
delete element.newValues;
return {...element, ...newValues};
});
console.log(updates);
It will work even if a value of newValues was not present into newValues.
The following answer is roughly equivalent to the one by JStw, with two key differences:
It uses Underscore instead of spread syntax;
It does not modify the elements of result.
This means that code is easier to reason about and potentially safer. Also, you don't need polyfills for the spread syntax.
const result = [
{
a: 1,
b: 2,
c: 3,
newValues: {
a: 10,
b: 20,
c: 30
}
},
{
d: 4,
e: 5,
f: 6,
newValues: {
d: 40,
e: 50
}
}
];
const updates = _.map(result, element =>
_.chain(element)
.omit('newValues')
.extend(element.newValues)
.value()
);
console.log(updates);
<script src="https://cdn.jsdelivr.net/npm/underscore#1.13.6/underscore-umd-min.js"></script>

map array of objects based on set of properties

Suppose I have an object:
let array = [
{a: 1, b: 5, c: 9},
{a: 2, b: 6, c: 10},
{a: 3, b: 7, c: 11},
{a: 4, b: 8, c: 12}
];
then I have a dictionary:
const columns = [
{ key: 'a', value: 'a' },
{ key: 'b', value: 'b' },
]
I want to filter out properties that are not defined in columns.
I have tried
array.map((x) => ({"a": x.a, "b": x.b}))
Is there a way to use the data defined in columns instead of manually typing all the properties?
Desired output:
[
{
"a": 1,
"b": 5
},
{
"a": 2,
"b": 6
},
{
"a": 3,
"b": 7
},
{
"a": 4,
"b": 8
}
]
You could map entries and get the new objects.
let
array = [{ a: 1, b: 5, c: 9 }, { a: 2, b: 6, c: 10 }, { a: 3, b: 7, c: 11 }, { a: 4, b: 8, c: 12 }],
columns = [{ key: 'a', value: 'a' }, { key: 'b', value: 'b' }],
keys = columns.map(({ key }) => key),
result = array.map(o => Object.fromEntries(keys.map(k => [k, o[k]])));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could use this.
This uses just an array to hold the desired columns because I don't get why you would use a dictionary with key and value being the same.
let array = [
{ a: 1, b: 5, c: 9 },
{ a: 2, b: 6, c: 10 },
{ a: 3, b: 7, c: 11 },
{ a: 4, b: 8, c: 12 },
];
const desiredColumns = ["a", "b"];
const transformed = array.map(item => {
const obj = {};
desiredColumns.forEach(col => {
if(col in item){
obj[col] = item[col];
}
})
return obj;
})
console.log(array);
console.log(transformed)
Another, slightly less direct way using map() and reduce():
Create an array with all the keys we'll keep
Reduce the array to get the desired result
Add current key + value if key keep array
const array = [{a: 1, b: 5, c: 9}, {a: 2, b: 6, c: 10}, {a: 3, b: 7, c: 11}, {a: 4, b: 8, c: 12} ];
const columns = [{ key: 'a', value: 'a' }, { key: 'b', value: 'b' }, ];
const toKeep = columns.map(({ key }) => key).flat();
const result = array.map(a =>
Object.keys(a)
.reduce((prev, cur) => (toKeep.includes(cur)) ? { ...prev, [cur]: a[cur] } : prev, {})
);
console.log(result);
Result:
[
{
"a": 1,
"b": 5
},
{
"a": 2,
"b": 6
},
{
"a": 3,
"b": 7
},
{
"a": 4,
"b": 8
}
]

Change structure of JavaScript array [duplicate]

This question already has answers here:
How can I group an array of objects by key?
(32 answers)
Closed 1 year ago.
I am a beginner in javascript and i have a little problem.
i want to change the structure of array for rendering in React Native using section List,
I got this JSON from Web Api
[
{
title: "Test",
c: 1,
d: 2,
},
{
title: "Test",
c: 3,
d: 4,
},
{
title: "Test",
c: 5,
d: 6,
},
{
title: "Test01",
c: 1,
d: 2,
},
{
title: "Test01",
c: 3,
d: 4,
},
{
title: "Test01",
c: 5,
d: 6,
},
{
title: "Test02",
c: 1,
d: 2,
},
{
title: "Test02",
c: 3,
d: 4,
},
{
title: "Test02",
c: 5,
d: 6,
},
];
And I want to change this JSON like this
[
{
title: "Test",
data: [
{ c: 1, d: 2 },
{ c: 3, d: 4 },
{ c: 5, d: 6 },
],
},
{
title: "Test01",
data: [
{ c: 1, d: 2 },
{ c: 3, d: 4 },
{ c: 5, d: 6 },
],
},
{
title: "Test02",
data: [
{ c: 1, d: 2 },
{ c: 3, d: 4 },
{ c: 5, d: 6 },
],
},
];
It would be simpler to key your data to the test name, but you can achieve what you want by mapping your array like this:
let new_array=[];
your_array.forEach(elem => {
let title = elem.title;
let matchingIndex = newArray.findIndex(a => a.title = title);
if (matchingIndex === -1) {
new_array.push({title}
matchingIndex = new_array.length - 1;
}
let dataColumns = ['c', 'd'];
let data = {};
dataColumns.forEach(col => {
data[col] = elem[col];
});
if (!Array.isArray(new_array[matching_index].data)) {
isArray(new_array[matching_index].data = [];
}
new_array[matching_index].data.push(data);
});
You can perform reduce operation in the array and get the desired format.
const items = [
{
title: "Test",
c: 1,
d: 2,
},
{
title: "Test",
c: 3,
d: 4,
},
{
title: "Test",
c: 5,
d: 6,
},
{
title: "Test01",
c: 1,
d: 2,
},
{
title: "Test01",
c: 3,
d: 4,
},
{
title: "Test01",
c: 5,
d: 6,
},
{
title: "Test02",
c: 1,
d: 2,
},
{
title: "Test02",
c: 3,
d: 4,
},
{
title: "Test02",
c: 5,
d: 6,
},
];
const formatted = items.reduce((carry, current) => {
// generating the placeholder format to put the data
if(!carry.hasOwnProperty(current.title)) {
carry[current.title] = {
title: current.title,
data: []
};
}
// Setting the data in unique name
carry[current.title].data.push({ c: current.c, d: current.d });
return carry;
}, []);
// formatted will have key value pair
console.log(Object.values(formatted));
A reduce function to accumulate the result in an array:
const raw = [{
title: 'Test',
c: 1,
d: 2,
},
{
title: 'Test',
c: 3,
d: 4,
},
{
title: 'Test',
c: 5,
d: 6,
},
{
title: 'Test01',
c: 1,
d: 2,
},
{
title: 'Test01',
c: 3,
d: 4,
},
{
title: 'Test01',
c: 5,
d: 6,
},
{
title: 'Test02',
c: 1,
d: 2,
},
{
title: 'Test02',
c: 3,
d: 4,
},
{
title: 'Test02',
c: 5,
d: 6,
},
];
const result = raw.reduce((acc, {
title,
...data
}) => {
const index = acc.findIndex((elem) => title === elem.title);
if (index === -1) acc.push({
title,
data: [data]
});
else acc[index].data.push(data);
return acc;
}, []);
console.log(result);
const input =[
{
title: "Test",
c: 1,
d: 2,
},
{
title: "Test",
c: 3,
d: 4,
},
{
title: "Test",
c: 5,
d: 6,
},
{
title: "Test01",
c: 1,
d: 2,
},
{
title: "Test01",
c: 3,
d: 4,
},
{
title: "Test01",
c: 5,
d: 6,
},
{
title: "Test02",
c: 1,
d: 2,
},
{
title: "Test02",
c: 3,
d: 4,
},
{
title: "Test02",
c: 5,
d: 6,
},
];
let result = {};
input.forEach((e)=>{
if(!result[e.title]){
result[e.title] = {data:[]};
}
result[e.title]['data'].push({ c:e.c, d:e.d});
});
let restructured =[];
Object.keys(result).forEach((key)=>{
restructured.push({
title: key, data:result[key].data
})
});
console.log(restructured)
var data = [
{
title: "Test",
c: 1,
d: 2,
},
{
title: "Test",
c: 3,
d: 4,
},
{
title: "Test",
c: 5,
d: 6,
},
{
title: "Test01",
c: 1,
d: 2,
},
{
title: "Test01",
c: 3,
d: 4,
},
{
title: "Test01",
c: 5,
d: 6,
},
{
title: "Test02",
c: 1,
d: 2,
},
{
title: "Test02",
c: 3,
d: 4,
},
{
title: "Test02",
c: 5,
d: 6,
},
];
console.log('data',data)
function analyse(data){
var tmp = {}
for(let item of data){
if(tmp[item.title]){
tmp[item.title].data.push({c:item.c,d:item.d})
}else{
tmp[item.title] ={
data: [{c:item.c,d:item.d}]
}
}
}
console.log('tmp',tmp)
var results = []
for(let key in tmp){
results.push({title:key,data:tmp[key].data})
}
console.log('results',JSON.stringify(results))
return results
}
analyse(data)

How can I summarize this array by dates

How can I summarize this array by dates ?
[
{ y: "2019-01-10", a: 25, b: 40, c: 10, d: 0 },
{ y: "2019-01-11", a: 25, b: 40, c: 10, d: 0 },
{ y: "2019-01-10", a: 10, b: 10, c: 0, d: 0 }
];
You can try Array reduce: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
const myArray = [ {y: "2019-01-10", a: 25, b: 40, c: 10, d: 0}, {y: "2019-01-11", a: 25, b: 40, c: 10, d: 0}, {y: "2019-01-10", a: 10, b: 10, c: 0, d: 0}];
const summaryObj = myArray.reduce((acc, item = {}) => {
// You can do something like this:
const date = item.y;// Just clarifying that "y" is a date for your purposes here.
const existingDateObj = acc[date] || {a: 0, b: 0, c: 0, d: 0};// Make sure a, b, c and d start out as numbers or your addition (undefined + 1) will result in `NaN`.
// You could/should do this in an immutable way, but that's a topic for another answer ;)
acc[date] = {
// Add the values from each item to the current, accumulated (summarized) values for the same date as `item.y`.
a: existingDateObj.a + item.a,
b: existingDateObj.b + item.b,
c: existingDateObj.c + item.c,
d: existingDateObj.d + item.d
};
return acc;
}, {});// The empty object {} is the initial accumulator. (The blank/empty/base version of the thing you ultimately intend to return.)
At that point, summaryObj will look like this:
{
"2019-01-10": {
"a": 35,
"b": 50,
"c": 10,
"d": 0
},
"2019-01-11": {
"a": 25,
"b": 40,
"c": 10,
"d": 0
}
}
If you want an array back, you can iterate the keys:
const myNewArray = Object
.keys(summaryObj)
.map(y => ({y, ...summaryObj[y]}));// Using object rest spread (...) for simplicity, it's the same as applying a, b, c and d (all the properties) for the current y value of summaryObj.
Then you would have this for myNewArray:
[
{
"y": "2019-01-10",
"a": 35,
"b": 50,
"c": 10,
"d": 0
},
{
"y": "2019-01-11",
"a": 25,
"b": 40,
"c": 10,
"d": 0
}
]
There are multiple ways to achieve this sort of task but this should give you some solid footing from which to base a solution.
NOTE: Some of the syntax here is ES6+ and may or may not be available depending on the JavaScript environment where you are running your code.
If you are looking for something like this, then here is the answer.
var array = [
{ y: "2019-01-10", a: 25, b: 40, c: 10, d: 0 },
{ y: "2019-01-11", a: 25, b: 40, c: 10, d: 0 },
{ y: "2019-01-10", a: 10, b: 10, c: 0, d: 0 }
];
function summarize(){
let summarize = {};
array.map(ele => {
const {a, b, c, d, y} = ele;
if(summarize[y]){
summarize[y] = {a: summarize[y].a + a, b: summarize[y].b + b, c: summarize[y].c + c, d: summarize[y].d + d};
}else{
summarize[y] = {a,b,c,d};
}
});
const keys = Object.keys(summarize);
const newArray = [];
keys.map(ele => {
const {a,b,c,d} = summarize[ele];
newArray.push({y: ele, a,b,c,d });
});
return newArray;
}
console.log(summarize());
This will give you out put as O/P
[
{"y":"2019-01-10","a":35,"b":50,"c":10,"d":0},
{"y":"2019-01-11","a":25,"b":40,"c":10,"d":0}
]
If you means to extract y (Date String) from this array then do Array.map
var data = [
{ y: "2019-01-10", a: 25, b: 40, c: 10, d: 0 },
{ y: "2019-01-11", a: 25, b: 40, c: 10, d: 0 },
{ y: "2019-01-10", a: 10, b: 10, c: 0, d: 0 }
];
var Dates = data.map(x => x.y);
console.log(Dates)

Adding a new element to an object in an array

Lets say I have and array made up of objects:
var points = [
{ id: 1, a: 0, b: 3 },
{ id: 2, a: 4, b: -1 },
{ id: 3, a: -1, b: 5 },
{ id: 4, a: 41, b: 2 },
{ id: 5, a: 69, b: 3 },
]
I want to iterate through each item and add a + b to get a new item d. I then want to add d within each object in the array to get a new value. When I try the below, it just adds 5 extra objects rather than appending the new element (key=value, ex: d: 3) to each individual object. What am I doing wrong here?
points.forEach((item) => {
var d = Math.abs(item.x) + Math.abs(item.y);
console.log(d);
points.item.push('d: ' + d);
});
Try following
var points = [{ id: 1, a: 0, b: 3 },{ id: 2, a: 4, b: -1 },{ id: 3, a: -1, b: 5 },{ id: 4, a: 41, b: 2 },{ id: 5, a: 69, b: 3 }];
points.forEach(o => o.d = Math.abs(o.a) + Math.abs(o.b));
console.log(points);
#jcbridwe, you can use assign() method on Object to add missing property from source object to target object.
Please have a look at the below code.
Try the below code online at http://rextester.com/EPHYV10615.
var points = [
{ id: 1, a: 0, b: 3 },
{ id: 2, a: 4, b: -1 },
{ id: 3, a: -1, b: 5 },
{ id: 4, a: 41, b: 2 },
{ id: 5, a: 69, b: 3 },
]
for(var index in points){
var a = points[index].a;
var b = points[index].b;
Object.assign(points[index], {d: a+b});
}
console.log(points);
ยป Output
[ { id: 1, a: 0, b: 3, d: 3 },
{ id: 2, a: 4, b: -1, d: 3 },
{ id: 3, a: -1, b: 5, d: 4 },
{ id: 4, a: 41, b: 2, d: 43 },
{ id: 5, a: 69, b: 3, d: 72 } ]
Mutable approach:
points.forEach(o => o.d = o.a + o.b);
Immutable approach:
const newPoints = points.map(o => Object.assign({}, o, {d: o.a + o.b}))

Categories

Resources