I want to add more key... value pairs to each of the objects. Is it possible to do that?
Right now I have objects that look like:
{"year":2014,"num":115.5}
{"year":2016,"num":0.0}
{"year":2017,"num":8.28}
{"year":2018,"num":0.0}
I have an array of colors:
let colors = ['#42d4f4','#e6194B','#3cb44b','#911eb4'];
I want to now add these colors to my objects.
I want to make it look like so:
{"year":2014,"num":115.5, "colors": '#42d4f4'}
{"year":2016,"num":0.0, "colors": '#e6194B'}
{"year":2017,"num":8.28, "colors": '#3cb44b'}
{"year":2018,"num":0.0, "colors": '#911eb4'}
Is there a way for me to do that without writing many many if's?
You can use map to loop thru the array. Use spread syntax to shallow copy the object and add the colors property using the index.
let arr = [{
"year": 2014,
"num": 115.5
}, {
"year": 2016,
"num": 0.0
}, {
"year": 2017,
"num": 8.28
}, {
"year": 2018,
"num": 0.0
}];
let colors = ['#42d4f4', '#e6194B', '#3cb44b', '#911eb4'];
let result = arr.map((o, i) => ({ ...o, colors: colors[i] || null }));
console.log(result);
If you want to update the existing variable, you can use forEach
let arr = [{
"year": 2014,
"num": 115.5
}, {
"year": 2016,
"num": 0.0
}, {
"year": 2017,
"num": 8.28
}, {
"year": 2018,
"num": 0.0
}];
let colors = ['#42d4f4', '#e6194B', '#3cb44b', '#911eb4'];
arr.forEach((o, i) => o.colors = colors[i] || null);
console.log(arr);
You can map over the array and return all of the objects with a new key color.
let data =[
{"year":2014,"num":115.5},
{"year":2016,"num":0.0},
{"year":2017,"num":8.28},
{"year":2018,"num":0.0}
];
let colors = ['#42d4f4','#e6194B','#3cb44b','#911eb4'];
let newData = colors.map((color, index) => ({...data[index], color}));
console.log(newData);
If you're not familiar with ES6 syntax, this is the same as:
let data =[
{"year":2014,"num":115.5},
{"year":2016,"num":0.0},
{"year":2017,"num":8.28},
{"year":2018,"num":0.0}
];
let colors = ['#42d4f4', '#e6194B', '#3cb44b', '#911eb4'];
let newData = colors.map(function(colorHex, index) {
return {
year: data[index].year,
num: data[index].num,
color: colorHex
}
})
console.log(newData) // [{"year":2014,"num":115.5, "colors": '#42d4f4'}, ...]
Related
I'm stuck on this type of situation where the values of the object is changed to a different value. Is there way to shift a value to a key or would simply deleting and adding be better? I tried to loop to see which of the keys overlap in value and using the if statement and conditions i tried adding or deleting using Array methods. However, since the inter data is an object i am sruggling to find the right methods or even the process. I also tried using a function to insert the data and pushing to a new empty array that is returned from the function.
If I have objects in an array like so:
const data = [
{
"date": "12/22",
"treatment": "nausea",
"count": 2
},
{
"date": "12/23",
"treatment": "cold",
"count": 3
},
{
"date": "12/22",
"treatment": "cold",
"count": 2
}
];
and wanting to change the data like so:
const newData = [
{
"date": "12/22",
"cold": 2
"nausea": 2,
},
{
"date": "12/23",
"cold": 3
}
];
try this code using loop and reduce and every time add to new array
const data = [
{
"date": "12/22",
"treatment": "nausea",
"count": 2
},
{
"date": "12/23",
"treatment": "cold",
"count": 3
},
{
"date": "12/22",
"treatment": "cold",
"count": 2
}
];
const newData = [];
const dataByDate = data.reduce((acc, curr) => {
if (!acc[curr.date]) {
acc[curr.date] = { date: curr.date };
}
acc[curr.date][curr.treatment] = curr.count;
return acc;
}, {});
for (let date in dataByDate) {
newData.push(dataByDate[date]);
}
console.log(newData);
We want to reduce the data by unique dates. This can be done with:
An object as a dictionary,
Set or Map, or
Some other custom implementation.
Prefer to use Array.reduce() when reducing an array. This is standardized and more expressive than a custom implementation.
Using a map-like structure as the accumulator allows reduction of the dates by uniqueness and the data itself, simultaneously.
Note: Properties of objects are converted to Strings (except for Symbols). So if you want to use different "keys" that are equal after conversion (e.g. 0 and "0"), you cannot use objects; use Map instead.
(All our dates are Strings already, so this warning does not apply here.)
When using an object we can use the nullish coalescing assignment ??=: This allows us to assign an initial "empty" entry ({ date: dataEntry.date }) when encountering a new unique date.
Further, that assignment evaluates to the dictionary's entry; the entry that was either already present or just assigned.
Then we only need to assign the treatment and its count as a key-value pair to the entry.
const data = [
{ "date": "12/22", "treatment": "nausea", "count": 2 },
{ "date": "12/23", "treatment": "cold", "count": 3 },
{ "date": "12/22", "treatment": "cold", "count": 2 }
];
const newData = reduceByDate(data);
console.log(newData);
function reduceByDate(data) {
const dataByDate = data.reduce((dict, dataEntry) => {
const dictEntry = dict[dataEntry.date] // Get existing or ...
??= { date: dataEntry.date }; // ... just initialized entry.
dictEntry[dataEntry.treatment] = dataEntry.count;
return dict;
}, {});
// Transform dictionary to array of reduced entries
return Object.values(dataByDate);
}
You can make use of reduce() and Object.assign().
First we use reduce to combine objects with the same date into one object and then use assign to merge the values:
const data = [{
"date": "12/22",
"treatment": "nausea",
"count": 2
},
{
"date": "12/23",
"treatment": "cold",
"count": 3
},
{
"date": "12/22",
"treatment": "cold",
"count": 2
}
];
const newData = data.reduce((acc, curr) => {
const dateIndex = acc.findIndex(item => item.date === curr.date);
if (dateIndex === -1) {
acc.push({
date: curr.date,
[curr.treatment]: curr.count
});
} else {
acc[dateIndex] = Object.assign({}, acc[dateIndex], {
[curr.treatment]: curr.count
});
}
return acc;
}, []);
console.log(newData)
I have this object:
var ages = [{
"getasafieldDetail": {
"id": "xxx",
"asaentrySet": [{
"result": "ON",
"buy": {
"username": "Dis"
},
"offerSet": [{
"createdStr": "2001-08-09 at 11:52 pm",
"value": 5.0
}]
}]
}
}];
and i want to add an element and have an output like this:
var ages = [{
"getasafieldDetail": {
"id": "xxx",
"asaentrySet": [{
"result": "ON",
"buy": {
"username": "Dis"
},
"land": "111", // THIS <<<<------------
"offerSet": [{
"createdStr": "2001-08-09 at 11:52 pm",
"value": 5.0
}]
}]
}
}];
i tried using splice but not works...
ages.splice(ages[0]['getasafieldDetail']['asaentrySet'][0]['offerSet'],0,'"land": "111"');
ages.join();
There is the handy syntax of Destructuring assignments which helps with cutting and reassembling objects.
Edit
#FireFuro99 did point to the ES6/ES2015 spec which explicitly states how to preserve/handle an object's key-order at the object's creation time.
Thus one can say ...
Every JS engine which does support Destructuring assignment has to respect too any object's key order from/at this object's creation time.
const ages = [{
getasafieldDetail: {
id: "xxx",
asaentrySet: [{
result: "ON",
buy: {
username: "Dis",
},
offerSet: [{
createdStr: "2001-08-09 at 11:52 pm",
value: 5.0,
}],
}],
},
}];
const { result, buy, ...rest } = ages[0].getasafieldDetail.asaentrySet[0];
ages[0].getasafieldDetail.asaentrySet[0] = {
result,
buy,
land: "111",
...rest,
};
console.log({ ages });
.as-console-wrapper { min-height: 100%!important; top: 0; }
Splice only works on Arrays.
To make this work, convert your Object to an Array using Object.entries(), then use splice, and then convert it back to an object using Object.fromEntries().
const entrySet = Object.entries(ages[0]['getasafieldDetail']['asaentrySet'][0]);
entrySet.splice(2,0, ["land", "111"]);
ages[0]['getasafieldDetail']['asaentrySet'][0] = Object.fromEntries(entrySet);
This will insert the key-value pair at the the specified position.
The advantage this has over the destructuring assignment is, that you can specify the index, whereas destructuring is pretty hardcoded.
ages[0]["getasafieldDetail"]["asaentrySet"][0].land = '111' will create the key land in the first object in asaentrySet and assign the value 111. Key order is not guaranteed
var ages = [{
"getasafieldDetail": {
"id": "xxx",
"asaentrySet": [{
"result": "ON",
"buy": {
"username": "Dis"
},
"offerSet": [{
"createdStr": "2001-08-09 at 11:52 pm",
"value": 5.0
}]
}]
}
}];
ages[0]["getasafieldDetail"]["asaentrySet"][0].land = '111'
console.log(ages)
When it is an array of objects you could simple, add, passing the position that you want by editing the array like the example below:
let land = {land: 1111}
let ages = [{'a':11},'2', 'wd']
let new =[]
new.push(ages[1])
new.push(land)
ages[1] = new
console.log(ages)
output:
(3) [{…}, Array(2), "wd"]
You get what you want from the array, edit it, and put back in the same position, may it can help.
I have the Following JavaScript Object JSON1
{
"1": {
"Average": 32.31,
"Count": 19,
"Sum": 32.6,
"Color": "red"
},
"2": {
"Average": 32.72,
"Count": 18,
"Sum": 32.96,
"Color": "blue"
},
"3": {
"Average": 31.4,
"Count": 18,
"Sum": 31.48,
"Color": "green"
}
}
and I want to convert into the following format using javascript ES6 methods. JSON2
[{
"title": "Average",
"val1": 32.31,
"val2": 32.72,
"val3": 31.4
}, {
"title": "Count",
"val1": 19,
"val2": 18,
"val3": 18
}, {
"title": "Sum",
"val1": 32.6,
"val2": 32.96,
"val3": 31.48
}, {
"title": "Color",
"val1": "red",
"val2": "blue",
"val3": "green"
}]
Object.keys(json1).forEach((item, index) => {
let statsList = [];
Object.keys(json1[item]).forEach(objItem => {
statsList.push({
title: objItem,
val1: boxObj[1][objItem],
val2: boxObj[2][objItem],
val3: boxObj[3][objItem]
});
});
console.log(statsList)
});
var json1 = {
"1": {
"Average": 32.31,
"Count": 19,
"Sum": 32.6,
"Color": "red"
},
"2": {
"Average": 32.72,
"Count": 18,
"Sum": 32.96,
"Color": "blue"
},
"3": {
"Average": 31.4,
"Count": 18,
"Sum": 31.48,
"Color": "green"
}
};
Object.keys(json1).forEach((item, index) => {
let statsList = [];
Object.keys(json1[item]).forEach(objItem => {
statsList.push({
title: objItem,
val1: boxObj[1][objItem],
val2: boxObj[2][objItem],
val3: boxObj[3][objItem]
});
});
console.log(statsList)
});
Here in the JSON1, the Number of objects can be any number. It has to format it Dynamically. In the JSON2, Instead of val1,val2 anything can be used uniquely identifiable keys in all the objects present in the array. I have tried using forEach, I was able to achieve it with static keys provided, and with the multiple looping statements. I just want with dynamic keys and avoiding multiple loops and I want to know what is the best and easiest way to do this formatting in Javascript. Advance Thanks for your help.
You may traverse source Object.values() with Array.prototype.reduce() to make up an object that will map each category to all possible values.
Then, you may Array.prototype.map() resulting Object.entries() to return an array of objects with desired structure:
const src = {"1":{"Average":32.31,"Count":19,"Sum":32.6,"Color":"red"},"2":{"Average":32.72,"Count":18,"Sum":32.96,"Color":"blue"},"3":{"Average":31.4,"Count":18,"Sum":31.48,"Color":"green"}},
resultMap = Object
.values(src)
.reduce((r,o,i) => (
Object
.entries(o)
.forEach(([key,value]) =>
(r[key]=r[key]||{}, r[key][`value${i+1}`] = value))
,r),{}),
result = Object
.entries(resultMap)
.map(([name,{...values}]) => ({name,...values}))
console.log(result)
.as-console-wrapper{min-height:100%;}
If only unique items in each category are required, you may somewhat modify above solution, making use of Set():
const src = {"1":{"Average":32.31,"Count":19,"Sum":32.6,"Color":"red"},"2":{"Average":32.72,"Count":18,"Sum":32.96,"Color":"blue"},"3":{"Average":31.4,"Count":18,"Sum":31.48,"Color":"green"}},
resultMap = Object
.values(src)
.reduce((r,o,i) => (
Object
.entries(o)
.forEach(([key,value]) =>
(r[key]=r[key]||(new Set()), r[key].add(value)))
,r),{}),
result = Object
.entries(resultMap)
.map(([name,values]) => ({
name,
...([...values].reduce((r,v,i) => (r[`value${i+1}`]=v, r),{}))
}))
console.log(result)
.as-console-wrapper{min-height:100%;}
You may see your data as a matrix: each row is a feature and each column a dimension
What you have is the data expressed a rows
And what you would like is the data expressed as columns
So what you want is the transpose of your matrix
Let's recall that taking the transpose can be done as: T[j][i] = M[i][j] forall i,j
In your case
for each index of row i in M
for each index of column j in M
// T[j] is your aggregated record
// i being the index of the row has to be renamed 'val'+i
// and you add the property: title: columnOfJ to record T[j]
T[j]['val' + i] = M[i][j]
T[j].title = col corresponding to index j
const M = {"1":{"Average":32.31,"Count":19,"Sum":32.6,"Color":"red"},"2":{"Average":32.72,"Count":18,"Sum":32.96,"Color":"blue"},"3":{"Average":31.4,"Count":18,"Sum":31.48,"Color":"green"}}
const T = []
Object.entries(M).forEach(([i, Mi]) => {
Object.keys(Mi).forEach((col, j) => {
T[j] = T[j] || {}
T[j].title = col // we just put the title before so it is the first entry in your record...
T[j]['val' + i] = Mi[col]
})
})
console.log(T)
I want to use Lodash chain function to filter through an arrays nested array items and then return the full parent object.
Here is some dummy data from my use case to illustrate my issue:
const capital = [
{
"financeCategory": "Loans",
"financeCategoryId": "22HM6fFFwx9eK2P42Onc",
"financeElements": [
{
"financeCategoryId": "22HM6fFFwx9eK2P42Onc",
"financeElementId": "JQiqqvGEugVQuI0fN1xQ",
"financeElementTitle": "Convertible loan",
"data": [
{
"month": 1,
"value": 100,
"year": "2020"
},
{
"month": 1,
"value": 100,
"year": "2019"
},
],
}
]
},
{
"financeCategory": "Investments",
"financeCategoryId": "JtnUsk5M4oklIFk6cAlL",
"financeElements": []
},
{
"financeCategory": "Ownerships Contribution",
"financeCategoryId": "PaDhGBm5uF0PhKJ1l6WX",
"financeElements": []
}
];
I want to filter on the "data" array within the financeElements and then return full expense object with the filter applied on "data".
Let's say I want to manipulate the expense object and only get the data on the financeElements that have the year 2020. I've tried like so:
const expenseFiltered: any = _.chain(expenses)
.flatMap('financeElements')
.flatMap('data')
.filter({year: '2020' as any}).value();
But that just gives me the filtered "data" objects.
Output:
[{
"month": 1,
"value": 100,
"year": "2020"
}]
Now I know there are ways that I could use that to produce the full object with the filtered data, but I really want to do this in just one simple _.chain command
Desired output
[
{
"financeCategory": "Loans",
"financeCategoryId": "22HM6fFFwx9eK2P42Onc",
"financeElements": [
{
"financeCategoryId": "22HM6fFFwx9eK2P42Onc",
"financeElementId": "JQiqqvGEugVQuI0fN1xQ",
"financeElementTitle": "Convertible loan",
"data": [
{
"month": 1,
"value": 100,
"year": "2020"
}
],
}
]
},
{
"financeCategory": "Investments",
"financeCategoryId": "JtnUsk5M4oklIFk6cAlL",
"financeElements": []
},
{
"financeCategory": "Ownerships Contribution",
"financeCategoryId": "PaDhGBm5uF0PhKJ1l6WX",
"financeElements": []
}
]
Is this possible using lodash chain?
A chain is used to transform a structure in several steps. In your case, you don't want to change the structure. You can use nested Array.map() (or lodash's _.map()) calls to iterate and rebuild the structure, and internally _.filter() the data:
const capital = [{"financeCategory":"Loans","financeCategoryId":"22HM6fFFwx9eK2P42Onc","financeElements":[{"financeCategoryId":"22HM6fFFwx9eK2P42Onc","financeElementId":"JQiqqvGEugVQuI0fN1xQ","financeElementTitle":"Convertible loan","data":[{"month":1,"value":100,"year":"2020"},{"month":1,"value":100,"year":"2019"}]}]},{"financeCategory":"Investments","financeCategoryId":"JtnUsk5M4oklIFk6cAlL","financeElements":[]},{"financeCategory":"Ownerships Contribution","financeCategoryId":"PaDhGBm5uF0PhKJ1l6WX","financeElements":[]}];
const expenseFiltered = capital.map(ex => ({
...ex,
financeElements: ex.financeElements.map(fe => ({
...fe,
data: _.filter(fe.data, { year: '2020' })
}))
}));
console.log(expenseFiltered);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
I'm about to show the data I aggregated from the database in a grouped histogram.
The data looks like this:
[
{
"_id": "Gas Separator Filter",
"sellingPrice": 100000,
"quantity": 10
},
{
"_id": "Dry Gas Cartridge",
"sellingPrice": 6005000,
"quantity": 15
}
]
But in order to show it in the chart and for them to be grouped, I need something like this. For each _id in the dataset above I should be able to see two bars in the chart.
[
{
"name": "quantity",
"Gas Separator Filter": 10,
"Dry Gas Cartridge": 15
},
{
"name": "sellingPrice",
"Gas Separator Filter": 100000,
"Dry Gas Cartridge": 6005000
}
]
It's been two hours and I'm not able to think of a good way to do this. What will you suggest?
Here is one solution using old school for loops :)
const transform = (data, nameValues, keyProp) => {
const result = [];
for (const name of nameValues) {
const output = { name };
for (const value of data) {
output[value[keyProp]] = value[name];
}
result.push(output);
}
return result;
};
const result = transform(
[
{
"_id": "Gas Separator Filter",
"sellingPrice": 100000,
"quantity": 10
},
{
"_id": "Dry Gas Cartridge",
"sellingPrice": 6005000,
"quantity": 15
}
],
["sellingPrice", "quantity"],
"_id"
);
console.log(result);
You can use array.reduce to achieve this:
const arrayToArray = (array) => {
var ret = [{
"name": "price"
}, {
"name": "quantity"
}
];
return array.reduce((obj, item, idx, original) => {
ret[0][item._id] = original[idx].sellingPrice;
ret[1][item._id] = original[idx].quantity;
return ret;
}, 0)
}
Like this you set a variable with the base object that you fullfill with couple _id:value for price and quantity.
But is not an "elegant" way to do this. Are you sure you need this objects array structure to show the chart?
I find it hard to explain my solution but here's my take on it (you can add console.logs for different variables to follow the transformation ):
extract all the keys in the object, loop through them, the name would be that key, and use a nested loop to set the other keys and values :
const data = [ { "_id": "Gas Separator Filter", "sellingPrice": 100000, "quantity": 10 }, { "_id": "Dry Gas Cartridge", "sellingPrice": 6005000, "quantity": 15 } ]
const [_id, ...keys] = [...new Set(data.map(e => Object.keys(e)).flat())]
// console.log(keys) : ["sellingPrice", "quantity"]
const result = keys.map(key => {
const values = data.map(obj => ({
[obj._id]: obj[key]
}))
return Object.assign({
name: key
}, ...values);
})
console.log(result)