Another dumb moment for me. Spent hours through for loops, maps, reduce, dictionaries but just can't seem to figure it out. I have a json data that look like this
{
"timeline": [
{
"series": "series1",
"data": [
{
"date": "20200713T120000Z",
"value": 0
},
{
"date": "20200714T120000Z",
"value": 8
},
{
"date": "20200715T120000Z",
"value": 0
}
]
},
{
"series": "series2",
"data": [
{
"date": "20200713T120000Z",
"value": 0
},
{
"date": "20200714T120000Z",
"value": 0
}
]
},
{
"series": "series3",
"data": [
{
"date": "20200713T120000Z",
"value": 1
},
{
"date": "20200714T120000Z",
"value": 0
}
]
},
{
"series": "series4",
"data": [
{
"date": "20200713T120000Z",
"value": 2
},
{
"date": "20200714T120000Z",
"value": 4
}
]
}
]
}
I need it in this format
[
{
date: "20200713T120000Z",
series1: 0,
series2: 0,
series3: 1,
series4: 2
},
{
date: "20200714T120000Z",
series1: 8,
series2: 0,
series3: 0,
series4: 4
}
]
Need to do this in JavaScript. Any help/ pointers will be much appreciated.
You could take an object forgrouping and an array for storing all keys for getting an ordered result with all same keys.
This approach filters all zero values from the result set.
const
data = { timeline: [{ series: "series1", data: [{ date: "20200713T120000Z", value: 0 }, { date: "20200714T120000Z", value: 8 }, { date: "20200715T120000Z", value: 0 }] }, { series: "series2", data: [{ date: "20200713T120000Z", value: 0 }, { date: "20200714T120000Z", value: 0 }] }, { series: "series3", data: [{ date: "20200713T120000Z", value: 1 }, { date: "20200714T120000Z", value: 0 }] }, { series: "series4", data: [{ date: "20200713T120000Z", value: 2 }, { date: "20200714T120000Z", value: 4 }] }] },
keys = ['date'],
result = Object
.values(data.timeline.reduce((r, { series, data }) => {
keys.push(series);
data.forEach(({ date, value }) => {
if (!value) return;
if (!r[date]) r[date] = { date };
r[date][series] = value;
});
return r;
}, {}))
.map(o => ({ ...Object.fromEntries(keys.map(k => [k, 0])), ...o }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This is temporary solution for this, you can try this. I'm using lodash, so please install it.
var _ = require('lodash')
const data = {"timeline": [ { "series": "series1", "data": [ { "date": "20200713T120000Z", "value": 0 },{ "date": "20200714T120000Z", "value": 8 },{ "date": "20200715T120000Z", "value": 0 }] },{ "series": "series2", "data": [ { "date": "20200713T120000Z", "value": 0 },{ "date": "20200714T120000Z", "value": 0 }] },{ "series": "series3", "data": [ { "date": "20200713T120000Z", "value": 1 },{ "date": "20200714T120000Z", "value": 0 }] },{ "series": "series4", "data": [ { "date": "20200713T120000Z", "value": 2 },{ "date": "20200714T120000Z", "value": 4 }] }] }
const t = _.flattenDeep(data.timeline.map(i => i.data.map(d => ({...d, series: i.series}))))
const result = t.reduce((acc, i) => {
const index = acc.findIndex(a => a.date === i.date)
if(index !== -1){
acc[index] = {
...acc[index],
[i.series]: i.value
}
}else {
acc.push({
date: i.date,
[i.series]: i.value
})
}
return acc
}, [])
console.log(result)
Use multiple forEach loops and build an object to track. Then get Object.values
const convert = (arr) => {
const res = {};
arr.forEach(({ series, data }) =>
data.forEach(
({ date, value }) =>
(res[date] = { ...(res[date] ?? { date }), [series]: value })
)
);
return Object.values(res);
};
obj = {"timeline": [ { "series": "series1", "data": [ { "date": "20200713T120000Z", "value": 0 },{ "date": "20200714T120000Z", "value": 8 },{ "date": "20200715T120000Z", "value": 0 }] },{ "series": "series2", "data": [ { "date": "20200713T120000Z", "value": 0 },{ "date": "20200714T120000Z", "value": 0 }] },{ "series": "series3", "data": [ { "date": "20200713T120000Z", "value": 1 },{ "date": "20200714T120000Z", "value": 0 }] },{ "series": "series4", "data": [ { "date": "20200713T120000Z", "value": 2 },{ "date": "20200714T120000Z", "value": 4 }] }] }
const res = convert(obj.timeline);
console.log(res)
Related
This question already has answers here:
How do I create new arrays from a parent array?
(3 answers)
Closed 6 months ago.
I am stuck in one scenario where needs to add new array object called "timeSeriesData" and "units" inside the each parent array object and needs to copy values inside the "timeSeriesData" from parent object.
Please do help me on this, it would be really appreciated.
Input -
{
"1": [
{
"date": 1638334800,
"value": 0
},
{
"date": 1638334800,
"value": 0
}
],
"2": [
{
"date": 1638334800,
"value": 19.71
},
{
"date": 1638334800,
"value": 23.77
}
],
"nth": [
{
"date": 1638334800,
"value": 19.71
},
{
"date": 1638334800,
"value": 19.71
}
]
}
Expected Output -
1: {
timeSeriesData: [
{
date: 1638334800,
value: 0,
},
{
date: 1638334900,
value: 0,
}
], units: '%'
},
2: {
timeSeriesData: [
{
date: 1638334900,
value: 19.71,
},
{
date: 1638334800,
value: 23.77,
}
], units: '%'
},
nth: {
timeSeriesData: [
{
date: 1638334900,
value: 19.71,
},
{
date: 1638334800,
value: 19.71,
}
], units: '%'
}
This solution will mutate the original object to have the shape and properties you are looking for. Basically it loops through each property using a for...in loop and reassigns the value of the prop to an object which has the array as timeSeriesData and a new unit prop.
for(let number in theObject){
theObject[number] = {
timeSeriesData: theObject[number],
units: '%'
}
}
console.log(theObject);
<script>
const theObject = {
"1": [
{
"date": 1638334800,
"value": 0
},
{
"date": 1638334800,
"value": 0
}
],
"2": [
{
"date": 1638334800,
"value": 19.71
},
{
"date": 1638334800,
"value": 23.77
}
],
"nth": [
{
"date": 1638334800,
"value": 19.71
},
{
"date": 1638334800,
"value": 19.71
}
]
}</script>
You only need is for loop here:
for(let key in array){
array[key] = {
timeSeriesData: array[key],
units: '%'
}
}
I have an array of objects coming from backend.
var values = [
{
"name": "Patient Introductions",
"series": [
{
"name": "Organization ABC",
"value": 3
}
]
},
{
"name": "Patient Assessment",
"series": [
{
"name": "Organization ABC",
"value": 2.5
}
]
},
{
"name": "Patient Introductions",
"series": [
{
"name": "Organization XYZ",
"value": 2.5
}
]
},
{
"name": "Patient Assessment",
"series": [
{
"name": "Organization XYZ",
"value": 3.3
}
]
},
];
I want to combine the inner array's objects and get one single array of objects for same name of objects.
var output = [
{
"name": "Patient Introductions",
"series": [
{
"name": "Organization ABC",
"value": 3
},
{
"name": "Organization XYZ",
"value": 2.5
}
]
},
{
"name": "Patient Assessment",
"series": [
{
"name": "Organization ABC",
"value": 2.5
},
{
"name": "Organization XYZ",
"value": 3.3
}
]
},
];
I think, I need to use reduce but not sure how I can combine objects of series of same name.
Please help and guide. Thanks
You are right with reducer
var values = [
{
"name": "Patient Introductions",
"series": [
{
"name": "Organization ABC",
"value": 3
}
]
},
{
"name": "Patient Assessment",
"series": [
{
"name": "Organization ABC",
"value": 2.5
}
]
},
{
"name": "Patient Introductions",
"series": [
{
"name": "Organization XYZ",
"value": 2.5
}
]
},
{
"name": "Patient Assessment",
"series": [
{
"name": "Organization XYZ",
"value": 3.3
}
]
},
];
var result = values.reduce((acc, curr) => {
var existing = acc.find(element => element.name === curr.name);
if(existing) {
existing.series.push(...curr.series);
} else {
acc.push(curr);
}
return acc;
}, []);
console.log(result);
Make a new empty array
loop through your original array if the name does not exist in the
new array then add to it'
if the name existed just add the new array to it
this way ensures no duplicate name will be in the array
var values = [
{
name: "Patient Introductions",
series: [
{
name: "Organization ABC",
value: 3,
},
],
},
{
name: "Patient Assessment",
series: [
{
name: "Organization ABC",
value: 2.5,
},
],
},
{
name: "Patient Introductions",
series: [
{
name: "Organization XYZ",
value: 2.5,
},
],
},
{
name: "Patient Assessment",
series: [
{
name: "Organization XYZ",
value: 3.3,
},
],
},
];
let newValues = [];
values.forEach((value) => {
let index = newValues.findIndex((item) => item.name === value.name);
if (index === -1) {
newValues.push({ name: value.name, series: [value.series[0]] });
} else {
newValues[index].series.push(value.series[0]);
}
});
console.log(newValues)
I want to compare a object with a string. To do so I JSON.stringify the object(date). How can I extract the value only? I could splice the result but thought about a faster solution. Any other possibilites how to get "10.09.2021" out of {"date":"10.09.2021"}?
var graph = {
"nodes": [
{
"id": 1,
"dates": [
{
"date": "10.09.2021"
},
{
"date": "12.10.2021"
}
]
}, {
"id": 2,
"dates": [
{
"date": "20.09.2021"
},
{
"date": "25.09.2021"
}
]
}, {
"id": 3,
"dates": [
{
"date": "07.10.2021"
},
{
"date": "12.10.2021"
}
]
}
]
}
graph.nodes.forEach(element => {
element.dates.forEach(date => {
strDate = JSON.stringify(date)
console.log(strDate) // {"date":"dd.mm.yyyy"}
//how to extract "dd.mm.yyyy" only?
if (strDate === "12.10.2021") {
console.log("true")
}
})
})
In stringify you just have to access the key of date object recieved in forEach. Please see below code
strDate = JSON.stringify(date.date) or strDate = JSON.stringify(date['date'])
you don't need to use stringify at all. just address it as regular object.
var graph = {
"nodes": [
{
"id": 1,
"dates": [
{
"date": "10.09.2021"
},
{
"date": "12.10.2021"
}
]
}, {
"id": 2,
"dates": [
{
"date": "20.09.2021"
},
{
"date": "25.09.2021"
}
]
}, {
"id": 3,
"dates": [
{
"date": "07.10.2021"
},
{
"date": "12.10.2021"
}
]
}
]
}
graph.nodes.forEach(element => {
element.dates.forEach(date => {
strDate = date.date;
console.log(date.date) // {"date":"dd.mm.yyyy"}
//how to extract "dd.mm.yyyy" only?
if (strDate === "12.10.2021") {
console.log("true")
}
})
})
This question already has answers here:
JavaScript - Sum the values of same ids of different objects in the array of objects
(9 answers)
Closed 1 year ago.
I have an array of object with different tax rate and its value. I'm trying to combine all values with same tax rate into single object. Below is my code
const arr = [
{
"taxes": [
{
"name": "CGST 2.5%",
"total": 4.01,
},
{
"name": "SGST 2.5%",
"total": 4.01,
},
],
},
{
"taxes": [
{
"name": "CGST 6%",
"total": 10,
},
{
"name": "SGST 6%",
"total": 10,
},
],
},
{
"taxes": [
{
"name": "CGST 2.5%",
"total": 16.42,
},
{
"name": "SGST 2.5%",
"total": 16.42,
},
],
},
{
"taxes": [
{
"name": "CGST 2.5%",
"total": 0,
},
{
"name": "SGST 2.5%",
"total": 0,
},
],
},
{
"taxes": [
{
"name": "CGST 6%",
"total": 12,
},
{
"name": "SGST 6%",
"total": 12,
},
],
},
];
const result = arr.map(item => {
return Object.values(item.taxes.reduce((r, { name, total }) => {
(r[name] || (r[name] = [name, 0]))[1] += total;
return r;
}, {}));
})
console.log(result);
I have searched and got reduce function which is working but I'm not able to make it to work with the nested arrays.
Kindly tolerate with my ability as I'm not at all familiar with the reduce function how it works.
What I wanted it will return me a new Array like
{ "CGST 2.5%": 20.43, "SGST 2.5%": 20.43, "CGST 6%": 22, "SGST 6%": 22 }
Simpler solution I can think of:
const result = {}
arr.forEach(el => {
el.taxes.forEach(tax => {
result[tax.name] = (result[tax.name] || 0)+ tax.total
})
})
const solution = Object.entries(result).map(el => ({name: el[0], total: el[1]}))
console.log(solution)
#Atal Shrivastava, I appreciate your attempt, This is very simple solation, 1st check if entry exist or not, if not create entry else increase entry...
Code:
const arr = [{ "taxes": [{ "name": "CGST 2.5%", "total": 4.01 }, { "name": "SGST 2.5%", "total": 4.01 },] }, { "taxes": [{ "name": "CGST 6%", "total": 10, }, { "name": "SGST 6%", "total": 10 },] }, { "taxes": [{ "name": "CGST 2.5%", "total": 16.42 }, { "name": "SGST 2.5%", "total": 16.42 },] }, { "taxes": [{ "name": "CGST 2.5%", "total": 0, }, { "name": "SGST 2.5%", "total": 0, },] }, { "taxes": [{ "name": "CGST 6%", "total": 12, }, { "name": "SGST 6%", "total": 12 },] }];
const result = arr.reduce((result, { taxes }) => {
for (const { name, total } of taxes)
if (result[name])
result[name] += total
else
result[name] = total
return result;
}, {})
console.log(result);
having an array with objects and inside an options array how do I filter the inner array of objects by key value?
Here is the following example:
let test = [{
"options": [{
"label": "Audi",
"value": 10
},
{
"label": "BMW",
"value": 18
},
{
"label": "Mercedes Benz",
"value": 116
},
{
"label": "VW",
"value": 184
}
],
"label": "test1"
},
{
"options": [{
"label": "Adler",
"value": 3664
},
{
"label": "Alfa Romeo",
"value": 3
},
{
"label": "Alpine",
"value": 4
}
],
"label": "test2"
}
]
how do I get back the object:
{
"label": "Audi",
"value": 10
}
if I filter with keyword Audi
return label.toLowerCase().includes(inputValue.toLowerCase());
I tried with the following
test.map((k) => {
res = k.options.filter((j) => {
inputValue.toLowerCase();
if (j.label.toLowerCase().includes(inputValue.toLowerCase())) {
return j;
}
});
});
You need to return the result of filter(), not just assign it to a variable, so that map() will return the results.
let test = [{
"options": [{
"label": "Audi",
"value": 10
},
{
"label": "BMW",
"value": 18
},
{
"label": "Mercedes Benz",
"value": 116
},
{
"label": "VW",
"value": 184
}
],
"label": "test1"
},
{
"options": [{
"label": "Adler",
"value": 3664
},
{
"label": "Alfa Romeo",
"value": 3
},
{
"label": "Alpine",
"value": 4
}
],
"label": "test2"
}
]
let inputValue = "audi";
let search = inputValue.toLowerCase();
let result = test.map(k => k.options.filter(j => j.label.toLowerCase().includes(search)));
console.log(result);
This will return all options matching the search query :
function find(array, query) {
return array.reduce((prev, current) => prev.concat(current.options), []).filter(item => item.label.includes(query))
}
find(test, 'Audi')
Use flatMap() followed by filter():
let test=[{options:[{label:"Audi",value:10},{label:"BMW",value:18},{label:"Mercedes Benz",value:116},{label:"VW",value:184}],label:"test1"},{options:[{label:"Adler",value:3664},{label:"Alfa Romeo",value:3},{label:"Alpine",value:4}],label:"test2"}]
let result = test.flatMap(el => {
return el.options.filter(car => car.label == "Audi")
})[0]
console.log(result)
You need to go two levels deep when traversing your array.
function filterArray(needle, haystack) {
return haystack
.map(h => h.options)
.flatMap(h => h )
.filter(h => h.label.toLowerCase().includes(needle.toLowerCase()));
CodeSandbox
This might gile your answer:
console.log(test[0].options[0]);