How can I summarize this array by dates - javascript

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)

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>

How to reshaping Data in Javascript from array to object without losing some of the data

I am trying to add the key to each so that I can be able to easy make a multi scatter plot in d3. . I am not sure how to do it.
EDIT: TO CLARIFY what I meant.
Data:
var dataOriginal = {
Apples: [{"A":4,"B":null,"C":null,"D":2}, {"A":5,"B":null,"C":3,"D":2}],
Oranges: [{"A":3,"B":1,"C":4,"D":4.3}],
Jackfruit: [{"A":5,"B":4,"C":4,"D":3}],
Avocado: [{"A":null,"B":33,"C":2,"D":9.66}],
Pomegranate: [{"A":5,"B":3.5,"C":null,"D":6}]
}
Function:
const data = Object.keys(dataOriginal).map((key) => {
const temp = {...dataOriginal[key]};
temp.key = key;
return temp;
});
Results:
0:
0: {A: 4, B: null, C: null, D: 2}
1: {A: 5, B: null, C: 3, D: 2}
key: "Apples"
__proto__: Object
1:
0: {A: 3, B: 1, C: 4, D: 4.3}
key: "Oranges"
__proto__: Object
2:
0: {A: 5, B: 4, C: 4, D: 3}
key: "Jackfruit"
__proto__: Object
3:
0: {A: null, B: 33, C: 2, D: 9.66}
key: "Avocado"
__proto__: Object
4: {0: {…}, key: "Pomegranate"}
Desired results
: {A: 4, B: null, C: null, D: 2, key: "Apples"}
1: {A: 3, B: 1, C: 4, D: 4.3, key: "Oranges"}
2: {A: 5, B: 4, C: 4, D: 3, key: "Jackfruit"}
3: {A: null, B: 33, C: 2, D: 9.66, key: "Avocado"}
4: {A: 5, B: 3.5, C: null, D: 6, key: "Pomegranate"}
5: {A:5,B:null,C:3,D:2, key: "Apples"}
You need to reduce the object to get a single object with added values.
const
addByKey = array => array.reduce((a, b) => {
Object.entries(b).forEach(([k, v]) => a[k] = (a[k] || 0) + v);
return a;
}, {}),
dataOriginal = { Apples: [{ A: 4, B: null, C: null, D: 2 }, { A: 5, B: null, C: 3, D: 2 }], Oranges: [{ A: 3, B: 1, C: 4, D: 4.3 }], Jackfruit: [{ A: 5, B: 4, C: 4, D: 3 }], Avocado: [{ A: null, B: 33, C: 2, D: 9.66 }], Pomegranate: [{ A: 5, B: 3.5, C: null, D: 6 }] }
data = Object.keys(dataOriginal).map((key) => ({ ...addByKey(dataOriginal[key]), key }));
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
For getting single object with same keys, you could map the objects, add the key and get a flat array.
const
dataOriginal = { Apples: [{ A: 4, B: null, C: null, D: 2 }, { A: 5, B: null, C: 3, D: 2 }], Oranges: [{ A: 3, B: 1, C: 4, D: 4.3 }], Jackfruit: [{ A: 5, B: 4, C: 4, D: 3 }], Avocado: [{ A: null, B: 33, C: 2, D: 9.66 }], Pomegranate: [{ A: 5, B: 3.5, C: null, D: 6 }] }
data = Object
.keys(dataOriginal)
.flatMap(key => dataOriginal[key].map(o => ({ ...o, key })));
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
The reason why {"A":5,"B":null,"C":3,"D":2} is missed is because, index 0 is hardcoded in the code.
const temp = {...dataOriginal[key][0]};
Alternate solution:
var dataOriginal = {
Apples: [{"A":4,"B":null,"C":null,"D":2}, {"A":5,"B":null,"C":3,"D":2}],
Oranges: [{"A":3,"B":1,"C":4,"D":4.3}],
Jackfruit: [{"A":5,"B":4,"C":4,"D":3}],
Avocado: [{"A":null,"B":33,"C":2,"D":9.66}],
Pomegranate: [{"A":5,"B":3.5,"C":null,"D":6}]
}
const myData =[]
Object.keys(dataOriginal).map((key) => {
for (let i = 0; i < dataOriginal[key].length; i++) {
myData.push({...dataOriginal[key][i], key})
}
})
console.log(myData)

how to bundle objects in an array by date attribute

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.

(Lodash) Is there a method to check if an identical object exists (nested) in a collection?

I was wondering if there is a Lodash approach to this problem, which I would otherwise solve with a for loop. I would like to return true if collection contains one or more elements with nested object identical to c.
The below example would return true because collection[1] contains an identical c.
Needle:
c = {
x: 11,
y: 22,
z: 33
}
Haystack:
collection = [
{
a: 1,
b: 1,
c: {
x: 10,
y: 20,
z: 30
},
d: 1
},
{
a: 1,
b: 1,
c: {
x: 11,
y: 22,
z: 33
},
d: 1
},
{
a: 1,
b: 1,
c: {
x: 12,
y: 24,
z: 36
},
d: 1
}
]
This is different from questions such as How to do a deep comparison between 2 objects with lodash? because I need to check if any of the collection items contain an identical object nested within them, not compare whether two objects are identical to each other.
Thanks in advance for your help.
You can use _.isEqual in a recursive function:
function find(h, n) {
if (_.isEqual(h, n)) return true;
let found;
if (Array.isArray(h)) {
for (let e of h) {
found = find(e, n);
if (found) return found;
}
} else if (h instanceof Object) {
return find(Object.values(h), n);
}
return false;
}
var c = {
x: 11,
y: 22,
z: 33
};
var d = {
x: 1111,
y: 2222,
z: 32223
};
var collection = [{
a: 1,
b: 1,
c: {
x: 10,
y: 20,
z: 30
},
d: 1
},
{
a: 1,
b: 1,
c: {
x: 11,
y: 22,
z: 33
},
d: 1
},
{
a: 1,
b: 1,
c: {
x: 12,
y: 24,
z: 36
},
d: 1
}
];
console.log(find(collection, c));
console.log(find(collection, d));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

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