How to aggregate objects with dates as keys in javascript - javascript

I have an object with keys as dates in the following format "yyyy-mm-dd" (ex: 2020-08-14)
the value of each key is an array of objects with two attributes, name and value.
I need to find a way to get the sum of the keyvalue grouped by name accros N days.
Here is an example to better understand, the original object have 4 days of data, with one day having an empty array:
{
"2020-10-15":[
{"name":"France","value":20},
{"name":"United States","value":20},
{"name":"Italy","value":5},
],
"2020-10-16":[
{"name":"Germany","value":10},
{"name":"United States","value":5},
{"name":"France","value":10}
],
"2020-10-17":[],
"2020-10-18":[
{"name":"UK","value":10},
{"name":"Italy","value":10},
]
}
For example if we wish to group this data by 4 days we will get the following:
[{"name": "France", "value": 30},
{"name": "United States", "value": 25},
{"name": "Italy", "value": 15},
{"name": "Germany", "value": 10},
{"name": "UK", "value": 10}]
This is the sum of all objects with same value for name across 4 days. I have absolutly no idea how to achieve this, I know can use map to iterate the object keys and do some processing through moment js but I don't know how to achieve this.

You can do the following using reduce, forEach and Object.keys method,
const value = {
"2020-10-15":[
{"name":"France","value":20},
{"name":"United States","value":20},
{"name":"Italy","value":5},
],
"2020-10-16":[
{"name":"Germany","value":10},
{"name":"United States","value":5},
{"name":"France","value":10}
],
"2020-10-17":[],
"2020-10-18":[
{"name":"UK","value":10},
{"name":"Italy","value":10},
]
}
let res = Object.keys(value).reduce((prev, curr) => {
value[curr].forEach(item => {
const idx = prev.findIndex(pItem => pItem.name === item.name);
if(idx > -1) {
const newObj = {...prev[idx], value: prev[idx].value + item.value};
prev[idx] = newObj;
return ;
}
prev.push(item);
})
return prev;
}, []);
console.log(res);

Related

How to remove duplicates form object of arrays [duplicate]

This question already has answers here:
map function for objects (instead of arrays)
(39 answers)
Closed 3 months ago.
I am trying to remove duplicate form list of arrays that are present in an object and object looks like bellow , for example i am only using two array but there are many in actual array that i am looking at
{
"NAME":[
"LORD",
"OF",
"RINGS",
"LORD"
],
"ADRESS":[
"INDIA",
"INDIA",
"TEXAS",
"SRILANKA"
]
}
Expected output :
{
"NAME":[
"LORD",
"OF",
"RINGS"
],
"ADRESS":[
"INDIA",
"TEXAS",
"SRILANKA"
]
}
Currently I am able to pull out a single array from object and am able to remove duplicates using "SET" bellow is my code
console.log("without duplicates", [... new Set(r.NAME)]);
Since it is an object i am sure i cant loop on this. How can i achieve the expected output , Thanks
You can iterate over the object keys and then use Set to remove duplicates like so:
function removeDuplicates(obj): any {
for (const key of Object.keys(obj)) {
obj[key] = [...new Set(obj[key])];
}
return obj;
}
const obj = {
NAME: ["LORD", "OF", "RINGS", "LORD"],
ADDRESS: ["INDIA", "INDIA", "TEXAS", "SRILANKA"]
};
//get array of keys
const keys = Object.keys(obj);
//then map to transform the object array
const sets = keys.map(key => new Set(obj[key]));
//set back to array
keys.forEach((key, i) => {
obj[key] = [...sets[i]];
});
console.log(obj);
We can use Set to remove the duplicate
let data = {
"NAME":[
"LORD",
"OF",
"RINGS",
"LORD"
],
"ADRESS":[
"INDIA",
"INDIA",
"TEXAS",
"SRILANKA"
]
}
Object.keys(data).forEach(k => {
data[k] = [...new Set(data[k])]
})
console.log(data)
How about this way?
const originDatas = {
"NAME":[
"LORD",
"OF",
"RINGS",
"LORD",
],
"ADRESS":[
"INDIA",
"INIDA",
"TEXAS",
"SRILANKA",
],
};
const setDatas = {};
Object.keys(originDatas).map((key) => {
setDatas[key] = [...new Set(originDatas[key])];
});
console.log(setDatas);

Get unique values and their amounts from an array of objects

So I get a JSON request that sends an array of objects with two properties, I need to extract the unique values and their quantities.
This is the JSON that is being sent via Postman:
[
{"name": "First value", "amount": 2},
{"name": "Second value", "amount": 4},
{"name": "First value", "amount": 6}
]
I need to return a JSON response with the unique values and their totals added up:
The object should look like this:
{
"First value": 8,
"Second value": 4
}
You can use reduce()
const arr = [
{"name": "First value", "amount": 2},
{"name": "Second value", "amount": 4},
{"name": "First value", "amount": 6}
]
const res = arr.reduce((ac, {name, amount}) => {
ac[name] = ac[name] || 0;
ac[name] += amount;
return ac;
},{})
console.log(res)
Explanation:
First of all we are initializing ac to an empty object {}. See the line
arr.reduce((ac, {name, amount}) => {...}
^^^^^^^^^^^^^^
The highlighted part is called Object destructuring. It will get the property name and amount out the current object through which we are iterating and make it independent variables.
See the line
ac[name] = ac[name] || 0;
Now this line is checking if ac[name] doesn't exist on the ac object then it will be undefined so undefined || 0 will be evaluate to 0. If it will have a value the value of ac[name] will remain as previous.
See the third line:
ac[name] += amount;
This line will add the amount to already value of ac[name]
At last we return ac so that it will be become initial value of ac for next iteration.
You could also simply use Array.forEach as it is for the most part easier to understand and follow:
let arr = [{ "name": "First value", "amount": 2 }, { "name": "Second value", "amount": 4 }, { "name": "First value", "amount": 6 } ],
obj={}
arr.forEach(({name, amount}) => {
obj[name] = obj[name] || 0
obj[name] += amount
})
console.log(obj)
The main difference here is that our accumulator (the obj) is defined outside rather than "internally" as an argument to the Array.reduce function.

converting array to object while considering keys of the same value

I am trying to figure out an easy way to convert an array of objects to an object
I have an array of objects that looks like this:
[
{
"id": "-LP9_kAbqnsQwXq0oGDT",
"value": Object {
"date": 1541482236000,
"title": "First",
},
},
.... more objects here
]
And id like to convert it to an object with the timestamps as the keys, and arrays of objects corresponding to that date. If that key already exists, then add the object to the corresponding array associated with that key
{
1541482236000:
[{
"id": "-LP9_kAbqnsQwXq0oGDT",
"value": Object {
"date": 1541482236000,
"title": "First",
},
},
{
"id": "-LP9_kAbqnsQwXqZZZZ",
"value": Object {
"date": 1541482236000,
"title": "Some other title",
},
},
.... more objects here
],
1541482236001:
[{
"id": "-LP9_kAbqnsQ1234",
"value": Object {
"date": 1541482236001,
"title": "Another title",
},
},
.... more objects here
]
}
I was able to achieve something similar using reduce. However it does not handle adding objects to the array when their key already exists.
calendarReminders = action.value.reduce((obj, reminder) => {
dateKey = moment(reminder.value.date).format('YYYY-MM-DD')
obj[dateKey] = [reminder]
return obj;
}, {});
How can I do this?
You just need to check whether the object is already a key and if not add it with the value of an array. Then you can just push() into it:
let arr = [{"id": "-LP9_kAbqnsQwXq0oGDT","value": {"date": 1541482236000,"title": "First",},},{"id": "SomID","value": {"date": 1541482236000,"title": "Some other title",},},{"id": "A different ID","value": {"date": 1541482236001,"title": "A third title",},}]
let calendarReminders = arr.reduce((obj, reminder) => {
(obj[reminder.value.date] || (obj[reminder.value.date] = [])).push(reminder)
return obj;
}, {});
console.log(calendarReminders)
If you want to set the keys to a different format with moment, you should be able to do that without changing the basic idea.
Please test the below code!
First you iterate through your array of data,
if your result object/dictionary already has the key then you just add the current item
otherwise you make the key and set the value
const data = [];
let result = {};
for (const item of data) {
const key = item.value.date;
if (result.hasOwnProperty(key)) {
const prevData = result[key];
result[key] = [...prevData, item];
} else {
result[key] = [item];
}
}

How to create a new json out of three jsons?

I have 3 different jsons, I need to extrapolate some data from each and create a new json with it. The three jsons have an id identifier in common, a unique identifier, so We could use that as a match since they are actually three different big jsons.
On json one we have "id":"265", on two and three "article_id":"265", so these can be the reference point when we loop.
I never worked with json this way so I wouldn't know how to approach it. I have put jQuery and JS as tags as they're what I know best.
1
{
"id":"265",
"title":"Battle of Gettysburg",
"page_id":"4849",
"language_id":"en",
"original_time":"July 1\u20133, 1863"
}
2
{
"id":"185",
"original_name":"United States",
"country_id":"24",
"article_id":"265"
}
3
{
"id":"73",
"month":"July",
"year":"1863",
"suffix":"",
"article_id":"265"
}
So the end result I am looking for is a single json exactly like this, we take id and title as objects from json 1, then we grab original_name from json two and year object from json three and we'll have:
{
"id":"265",
"title":"Battle of Gettysburg",
"original_name":"United States",
"year":"1863"
}
NOTE
The json above are just examples, in reality they are three huge lists, what I could do (manually), is to join them in order to have a single json.
There is some terminology confusion here; based on your comments you could be asking one of two very different questions. Fortunately one of them is very simple to answer so let's do both.
(I am handwaving past the details of loading json strings into the browser and converting them into javascript objects.)
If you have three objects
...then this is just a matter of plucking out the fields you need individually when constructing an output object:
var in1 = {
"id": "265",
"title": "Battle of Gettysburg",
"page_id": "4849",
"language_id": "en",
"original_time": "July 1\u20133, 1863"
};
var in2 = {
"id": "185",
"original_name": "United States",
"country_id": "24",
"article_id": "265"
}
var in3 = {
"id": "73",
"month": "July",
"year": "1863",
"suffix": "",
"article_id": "265"
}
// construct a new object using the selected fields
// from each object in1, in2, or in3:
var out = {
id: in1.id,
title: in1.title,
original_name: in2.original_name,
year: in3.year
}
console.log(out);
If you have three lists of objects:
...in this case it's a lot more complicated (and a lot more interesting). In this case you would need to match fields from the objects in each list which share the same IDs.
The following is definitely not the most efficient or memory-conserving way to do this; I've spread things out to (hopefully) make it easier to follow what it's doing.
I'm making two assumptions:
within each list, all IDs are unique (meaning you won't have two objects with the same ID in one JSON file)
Every ID will appear in all three lists (meaning you don't need to handle missing fields in output)
/* Again handwaving past loading JSON strings and parsing
them into javascript objects, we'll just start with
three arrays: */
var input1 = [{
"id": "265",
"title": "Battle of Gettysburg",
"page_id": "4849",
"language_id": "en",
"original_time": "July 1\u20133, 1863"
},
{
"id": "1",
"title": "Foo",
"page_id": "123",
"language_id": "en",
"original_time": "July 1\u20133, 1863"
}
];
var input2 = [{
"id": "1",
"original_name": "Bar",
"country_id": "24",
"article_id": "265"
},
{
"id": "265",
"original_name": "United States",
"country_id": "24",
"article_id": "265"
}
]
var input3 = [{
"id": "1",
"month": "July",
"year": "Baz",
"suffix": "",
"article_id": "265"
},
{
"id": "265",
"month": "July",
"year": "1863",
"suffix": "",
"article_id": "265"
}
]
/* It would be much easier to find corresponding IDs
across these arrays if they weren't arrays. We'll
start by converting them into objects keyed by the
item ids: */
var convertArray = function(arr) {
var output = {};
arr.forEach(function(o) {
output[o.id] = o;
});
return output;
}
var obj1 = convertArray(input1);
var obj2 = convertArray(input2);
var obj3 = convertArray(input3);
/* Now if we need to find (say) the object with id "foo", we don't
need to search the whole array, but can just use `obj1["foo"]` or
`obj1.foo`.
The last step is to iterate over the list of IDs and repeatedly
do basically the same thing as in the "if you have three objects"
part above. The only difference is that we need to access the
object with the same ID in each of the input lists: */
var constructOutput = function(in1, in2, in3) {
var output = []; // we'll be outputting a list of objects again.
// step through every ID (assuming in1 contains all of them):
Object.keys(in1).forEach(function(id) {
var obj = {
id: id,
title: in1[id].title,
original_name: in2[id].original_name,
year: in3[id].year
}
output.push(obj);
});
return output;
}
var final = constructOutput(obj1, obj2, obj3)
console.log(final)
Essentially what you have to do is mimic a SQL JOIN using JavaScript objects:
Use JSON.parse() on all three JSON collections to turn them into arrays of objects.
Iterate through JSON 1 objects; for each object...
Iterate through JSON 2 objects, testing if article ID matches the ID from JSON 1 that we are iterating over. Save this object.
Iterate through JSON 3 objects, testing if ID matches the ID of the object we found from JSON 2. Save this object.
After you have all three objects, make a new object literal that contains only the fields you want:
{
Id: obj1.id,
Title: obj1.title,
Original_name: obj2.original_name,
Year: obj3.year
}
Should you want to combine n number of JSON objects, e.g. a list of objects you can take a functional approach and utilise reduce + filter.
const data = [{
"id":"265",
"title":"Battle of Gettysburg",
"page_id":"4849",
"language_id":"en",
"original_time":"July 1\u20133, 1863"
},
{
"id":"185",
"original_name":"United States",
"country_id":"24",
"article_id":"265"
},
{
"id":"73",
"month":"July",
"year":"1863",
"suffix":"",
"article_id":"265"
}];
const final = data.reduce((accu, { id, title }, index, array) => {
// Find any related objects
const matches = array.filter(data => data.article_id === id);
if (matches.length) {
// Flatten them for ease of access. Duplicate keys will override.
const flat = matches.reduce((arr, item) => ({ ...arr, ...item }), [])
// Return new object
return accu.concat({
...flat,
id,
title,
});
}
return accu;
}, []);
console.log(final, '<<')
// Witness
document.getElementById('results').innerHTML = JSON.stringify(final);
<div id="results" style="font-family: Courier; font-size 14px; color: #fff; background: #000; padding: 20px; max-width: 80vw;"></div>
Edited*
Maybe this is what you need?
let arrPages = [{
"id":"265",
"title":"Battle of Gettysburg",
"page_id":"4849",
"language_id":"en",
"original_time":"July 1\u20133, 1863"
}];
let arrArticles = [{
"id":"185",
"original_name":"United States",
"country_id":"24",
"article_id":"265"
},
{
"id":"73",
"month":"July",
"year":"1863",
"suffix":"",
"article_id":"265"
}];
let getResult = (arrInput, arrCompare) => {
let joinedItems = [];
arrInput.forEach(item => {
let newItem = { id: item.id, title: item.title };
arrCompare.forEach(subItem => {
if(subItem.article_id !== undefined && subItem.article_id === item.id){
if(subItem.original_name !== undefined)
newItem.original_name = subItem.original_name;
if(subItem.year !== undefined)
newItem.year = subItem.year;
}
});
joinedItems.push(newItem);
});
return joinedItems;
};
let result = getResult(arrPages, arrArticles);
console.log(result);
In the first part of the code i create a var that has the json data.
To solve the problema i create 2 functions, the order of the creation dosen't metter, the first function getJSONData() take the json data as parameter and return a object filtered by the keys defined in the array keys. The secound function just check if the current key is present in the array of keys, this function could be replaced by the jQuery.inArray() method.
// JSON data
var json = [{
"id":"265",
"title":"Battle of Gettysburg",
"page_id":"4849",
"language_id":"en",
"original_time":"July 1\u20133, 1863"
},
{
"id":"185",
"original_name":"United States",
"country_id":"24",
"article_id":"265"
},
{
"id":"73",
"month":"July",
"year":"1863",
"suffix":"",
"article_id":"265"
}]
// keys that i want
var keys = ["title", "original_name", "year"];
// var that will have the filtered data
var newJSON = getJSONData(json);
console.log(JSON.stringify(newJSON))
// this is the main function of the code
// here we iterate in the json creating a new object that has all the tags definid in the keys array
function getJSONData(arrayJSON){
var JSONFiltered = {};
for(var i in arrayJSON){
for(var key in arrayJSON[i]){
if(hasElement(key)){
JSONFiltered[key] = arrayJSON[i][key];
}
}
}
return JSONFiltered;
}
// this function is used to check a key is present in the array of keys
function hasElement(key){
for(var elem in keys){
if(keys[elem] == key) return true;
}
return false;
}

Is there an easy way to convert a Javascript Object into "name": "Fred", "value": "Blue" style pairs?

I'm positive this question must have been covered before, but I can quite find it. So....
I have an object like so
Object
name: Fred
lastname: Jones
city: Los Angeles
I'd like to use Javascript to convert it to a string that looks like this:
//Do want this
[
{"name": "name", "value": "Fred"},
{"name": "lastname", "value": "Jones"},
{"name": "city", "value": "Los Angeles"}
]
All of the examples I've found use JSON.parse() to get a result that looks like this (which I don't want):
//Don't want this
[
{"name": "Fred", "lastname": "Jones", "city": "Los Angeles"}
]
I'm working with another developer who says this is how Jquery parses objects (EDIT- he's using $serializeArray(), so perhaps JQuery has a method to help me with this.
Any ideas would be most welcome.
Thanks!
This conversion calls for iterating through the properties of the source object and accumulating entries in a result array.
function toList( obj ) {
var rv = [], k;
for (k in obj) {
if (obj.hasOwnProperty(k))
rv.push({ name: k, value: obj[k] });
}
return rv;
}
var list = toList( myObject );
var arr = []
for (var key in object_name) {
arr.push({'name': key, 'value': object_name[key]})
}
Loop through the keys and add it to the array.
You can loop through the object properties and create the array
var a = array();
for (p in obj) {
a.push({'name': p, 'value': obj[p]});
}
This should get the structure that you want.
You should be able to do it in a simple for..in loop.
var yourObject = { name: "Fred", lastname: "Jones", city: "Los Angeles" },
parsed = [];
for(var i in yourObject){
parsed.push({ name: i, value: yourObject[i]})
}

Categories