Having a json file in this format...
data =[
{
key: "london",
values: [
{day: "2020-01-01", city: "london", value: 10},
{day: "2020-01-02", city: "london", value: 20},
{day: "2020-01-03", city: "london", value: 30},
{day: "2020-01-04", city: "london", value: 30},
{day: "2020-01-05", city: "london", value: 30},
{day: "2020-01-06", city: "london", value: 30}
]
},
{
key: "berlin",
values: [
{day: "2020-01-01", city: "berlin", value: 10},
{day: "2020-01-02", city: "berlin", value: 15},
{day: "2020-01-03", city: "berlin", value: 30},
{day: "2020-01-04", city: "berlin", value: 30},
{day: "2020-01-05", city: "berlin", value: 30},
{day: "2020-01-06", city: "berlin", value: 45}
]
},
{
key: "rome",
values: [
{day: "2020-01-01", city: "rome", value: 10},
{day: "2020-01-02", city: "rome", value: 12},
{day: "2020-01-03", city: "rome", value: 6},
{day: "2020-01-04", city: "rome", value: 9},
{day: "2020-01-05", city: "rome", value: 27},
{day: "2020-01-06", city: "rome", value: 36}
]
}]
I was wondering how I can calculate the daily percentage change in the series using javascript. I am expecting to get the following output. If possible, I'd like to remove city in order not to repeat information.
data =[
{
key: "london",
values: [
{day: "2020-01-01", value: 10, perc: 0},
{day: "2020-01-02", value: 20, perc: 1},
{day: "2020-01-03", value: 30, perc: 1},
{day: "2020-01-04", value: 30, perc: 0},
{day: "2020-01-05", value: 30, perc: 0},
{day: "2020-01-06", value: 30, perc: 0}
]
},
{
key: "berlin",
values: [
{day: "2020-01-01", value: 10, perc: 0},
{day: "2020-01-02", value: 15, perc: 0.5},
{day: "2020-01-03", value: 30, perc: 1},
{day: "2020-01-04", value: 30, perc: 0},
{day: "2020-01-05", value: 30, perc: 0},
{day: "2020-01-06", value: 45, perc: 0.5}
]
},
{
key: "rome",
values: [
{day: "2020-01-01", value: 10, perc: 0},
{day: "2020-01-02", value: 12, perc: 0.2},
{day: "2020-01-03", value: 6, perc: -0.5},
{day: "2020-01-04", value: 9, perc: 0.5},
{day: "2020-01-05", value: 27, perc: 2},
{day: "2020-01-06", value: 36, perc: 0.33}
]
}]
Bonus question: What should I do in order to calculate percentage change for a different period of time (every two days, week, etc.) and get an output like the one below? (Showing percentage change every two days)
data =[
{
key: "london",
values: [
{day: "2020-01-01", value: 10, perc: 0},
{day: "2020-01-03", value: 30, perc: 2},
{day: "2020-01-05", value: 30, perc: 0},
]
},
{
key: "berlin",
values: [
{day: "2020-01-01", value: 10, perc: 0},
{day: "2020-01-03", value: 30, perc: 2},
{day: "2020-01-05", value: 30, perc: 0},
]
},
{
key: "rome",
values: [
{day: "2020-01-01", value: 10, perc: 0},
{day: "2020-01-03", value: 6, perc: -0.4},
{day: "2020-01-05", value: 27, perc: 4.5},
]
}]
Here's my take on this situation. It also includes the bonus question.
P.S.: This is my first stackoverflow post, if you have any questions please ask!
// Your input data
const data = [
{
key: "london",
values: [
{day: "2020-01-01", city: "london", value: 10},
{day: "2020-01-02", city: "london", value: 20},
{day: "2020-01-03", city: "london", value: 30},
{day: "2020-01-04", city: "london", value: 30},
{day: "2020-01-05", city: "london", value: 30},
{day: "2020-01-06", city: "london", value: 30}
]
},
{
key: "berlin",
values: [
{day: "2020-01-01", city: "berlin", value: 10},
{day: "2020-01-02", city: "berlin", value: 15},
{day: "2020-01-03", city: "berlin", value: 30},
{day: "2020-01-04", city: "berlin", value: 30},
{day: "2020-01-05", city: "berlin", value: 30},
{day: "2020-01-06", city: "berlin", value: 45}
]
},
{
key: "rome",
values: [
{day: "2020-01-01", city: "rome", value: 10},
{day: "2020-01-02", city: "rome", value: 12},
{day: "2020-01-03", city: "rome", value: 6},
{day: "2020-01-04", city: "rome", value: 9},
{day: "2020-01-05", city: "rome", value: 27},
{day: "2020-01-06", city: "rome", value: 36}
]
}];
// The parsed output data
const parsedData = data.map((obj) => {
// Maps the object values to calculate the percentage
return {...obj, values: obj.values.map((value, i) => {
// Delete the "city" key
delete value['city'];
// Can't calculate the percentage on the first element
if (i == 0)
return { ...value, perc: 0 };
// Get the current & previous day/value
const currentValue = value.value;
const currentDay = new Date(value.day);
const previousValue = obj.values[i-1].value;
const previousDay = new Date(obj.values[i-1].day);
// Calculate the days between the previous and current entry
const dayTimeDiff = Math.abs(currentDay - previousDay);
const dayDiff = Math.ceil(dayTimeDiff / (1000 * 60 * 60 * 24));
// Calculate the precentage = (current - previous) / previous
const percentDiff = currentValue - previousValue / previousValue / dayDiff;
return { ...value, perc: percentDiff };
})}
});
console.log(parsedData);
For the first part, you can manipulate each value inside values array:
const data = [
{
key: "london",
values: [
{day: "2020-01-01", city: "london", value: 10},
{day: "2020-01-02", city: "london", value: 20},
{day: "2020-01-03", city: "london", value: 30},
{day: "2020-01-04", city: "london", value: 30},
{day: "2020-01-05", city: "london", value: 30},
{day: "2020-01-06", city: "london", value: 30}
]
},
{
key: "berlin",
values: [
{day: "2020-01-01", city: "berlin", value: 10},
{day: "2020-01-02", city: "berlin", value: 15},
{day: "2020-01-03", city: "berlin", value: 30},
{day: "2020-01-04", city: "berlin", value: 30},
{day: "2020-01-05", city: "berlin", value: 30},
{day: "2020-01-06", city: "berlin", value: 45}
]
},
{
key: "rome",
values: [
{day: "2020-01-01", city: "rome", value: 10},
{day: "2020-01-02", city: "rome", value: 12},
{day: "2020-01-03", city: "rome", value: 6},
{day: "2020-01-04", city: "rome", value: 9},
{day: "2020-01-05", city: "rome", value: 27},
{day: "2020-01-06", city: "rome", value: 36}
]
}]
const newData = data.map((info) => {
const n = info.values.length;
const valuesCopy = info.values.map((info) => info.value);
for (let i = 0; i < n; i++) {
const currentValue = valuesCopy[i];
const previousValue = valuesCopy[i - 1];
// calculate the percentage
const percentage = (currentValue - previousValue) / previousValue;
// percentage is NaN return 0
// percentage is < 1, return 2 decimal places
// otherwise return percentage
info.values[i].value = !percentage ? 0 : percentage < 1 ? percentage.toFixed(2) : percentage;
}
return info;
})
console.log(JSON.stringify(newData, null, 2));
Example using simple for loops + comments:
const data =[
{
key: "london",
values: [
{day: "2020-01-01", city: "london", value: 10},
{day: "2020-01-02", city: "london", value: 20},
{day: "2020-01-03", city: "london", value: 30},
{day: "2020-01-04", city: "london", value: 30},
{day: "2020-01-05", city: "london", value: 30},
{day: "2020-01-06", city: "london", value: 30}
]
},
{
key: "berlin",
values: [
{day: "2020-01-01", city: "berlin", value: 10},
{day: "2020-01-02", city: "berlin", value: 15},
{day: "2020-01-03", city: "berlin", value: 30},
{day: "2020-01-04", city: "berlin", value: 30},
{day: "2020-01-05", city: "berlin", value: 30},
{day: "2020-01-06", city: "berlin", value: 45}
]
},
{
key: "rome",
values: [
{day: "2020-01-01", city: "rome", value: 10},
{day: "2020-01-02", city: "rome", value: 12},
{day: "2020-01-03", city: "rome", value: 6},
{day: "2020-01-04", city: "rome", value: 9},
{day: "2020-01-05", city: "rome", value: 27},
{day: "2020-01-06", city: "rome", value: 36}
]
}
];
// Define resulting array
const results = [];
// Loop data
for(let i = 0; i < data.length; i++) {
// Set city object
const city = {
key: data[i].key,
values: []
};
// Set shorcut to values
const dVal = data[i].values
// Loop values in city entry
for(let i = 0; i < dVal.length; i++) {
// Set previous value or current if it is first cycle
const prev = (i !== 0) ? dVal[i-1].value : dVal[i].value;
// Set current value
const cur = dVal[i].value;
// Calculate percentage
let percDiff = (cur - prev) / prev;
// Fancy result as you need
percDiff = parseFloat(percDiff.toFixed(2));
// Push to city object
city.values.push({
day: dVal[i].day,
value: dVal[i].value,
perc: percDiff
});
}
// Push city object to resulting array
results.push(city);
}
// Log
console.log(results);
Answer on your second question, if I get it right, is simple - remove day entries that you don't need from array and pass resulting array to the same function. It calculates difference between entries, doesn't matter it is day or week
Related
I'm trying to group array of objects by two properties so I get data on two levels. This is in JavaScript - Node server.
Here is the data I'm starting with
items = [
{month: 11, year: 2022, amount: 10},
{month: 12, year: 2022, amount: 6},
{month: 11, year: 2022, amount: 7},
{month: 12, year: 2022, amount: 12},
{month: 1, year: 2023, amount: 5},
{month: 1, year: 2023, amount: 15},
{month: 11, year: 2023, amount: 30},
{month: 11, year: 2023, amount: 20}
],
I need all items from the same month and in the same year grouped together. The final result would look like this:
result = {
"2022": {
"11": [
{month: 11, year: 2022, amount: 10},
{month: 11, year: 2022, amount: 7}
],
"12": [
{month: 12, year: 2022, amount: 6},
{month: 12, year: 2022, amount: 12}
]
},
"2023": {
"11": [
{month: 11, year: 2023, amount: 30},
{month: 11, year: 2023, amount: 20}
],
"1": [
{month: 1, year: 2023, amount: 5},
{month: 1, year: 2023, amount: 15}
]
}
}
The first step is done quite easily, either through reduce or groupBy(), I've opted for groupBy() because it is cleaner:
const itemsPerYear = items.groupBy(item => { return item.year })
This gives me intermediate result:
itemsPerYear = {
"2022": [
{month: 11, year: 2022, amount: 10},
{month: 11, year: 2022, amount: 7},
{month: 12, year: 2022, amount: 6},
{month: 12, year: 2022, amount: 12}
],
"2023": [
{month: 11, year: 2023, amount: 30},
{month: 11, year: 2023, amount: 20},
{month: 1, year: 2023, amount: 5},
{month: 1, year: 2023, amount: 15}
]
}
So if I apply similar logic and go with:
const itemsPerMonth = Object.values(itemsPerYear).groupBy(item => { return item.month })
I get:
[Object: null prototype] {
undefined: [
[ [Object], [Object], [Object], [Object] ],
[ [Object], [Object], [Object], [Object] ]
]
}
I get a step closer with ForEach:
const itemsPerMonth = Object.values(itemsPerYear).forEach(sub => { console.log(sub) })
I get:
[
{month: 11, year: 2022, amount: 10},
{month: 11, year: 2022, amount: 7},
{month: 12, year: 2022, amount: 6},
{month: 12, year: 2022, amount: 12}
],
[
{month: 11, year: 2023, amount: 30},
{month: 11, year: 2023, amount: 20},
{month: 1, year: 2023, amount: 5},
{month: 1, year: 2023, amount: 15}
]
If I want to use groupBy() inside the ForEach() I get undefined.
Thanks
Here is a quick solution using a .reduce():
const input = [ {month: 11, year: 2022, amount: 10}, {month: 12, year: 2022, amount: 6}, {month: 11, year: 2022, amount: 7}, {month: 12, year: 2022, amount: 12}, {month: 1, year: 2023, amount: 5}, {month: 1, year: 2023, amount: 15}, {month: 11, year: 2023, amount: 30}, {month: 11, year: 2023, amount: 20} ];
const result = input.reduce((acc, obj) => {
if(!acc[obj.year]) acc[obj.year] = {};
if(!acc[obj.year][obj.month]) acc[obj.year][obj.month] = [];
acc[obj.year][obj.month].push(obj);
return acc;
}, {});
console.log('result:', result);
Docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
I'm using react-table to create an expandible table.
In that example data are in this format:
[
{
"firstName": "wheel",
"lastName": "arch",
"age": 29,
"visits": 39,
"progress": 87,
"status": "single",
"subRows": [
{
"firstName": "singer",
"lastName": "paper",
"age": 24,
"visits": 35,
"progress": 55,
"status": "complicated",
"subRows": [
{
"firstName": "professor",
"lastName": "beam",
"age": 22,
"visits": 14,
"progress": 84,
"status": "single"
}, {...}
]
},
]
}
{
"firstName": "elevator",
"lastName": "contribution",
"age": 26,
"visits": 74,
"progress": 28,
"status": "relationship",
"subRows": [
{
"firstName": "debt",
"lastName": "honey",
"age": 3,
"visits": 31,
"progress": 31,
"status": "relationship"
}, {...}
]
},
{
"firstName": "cup",
"lastName": "media",
"age": 8,
"visits": 77,
"progress": 37,
"status": "single",
"subRows": undefined
}
]
So an array of objects and each object has a property subRows that can be undefinedd or an array of objects.
I've a flat dataset, so an array of objects and I want to recreate the above structure grouping by a property.
For example, this is my dataset:
const data = [
{animal: 'cat', name: 'mu', year: 2016},
{animal: 'cat', name: 'muji', year: 2021},
{animal: 'cat', name: 'mine', year: 2021},
{animal: 'dog', name: 'fido', year: 2000},
{animal: 'hamster', name: 'gerry', year: 2020},
{animal: 't-rex', name: 'dino', year: 2020},
{animal: 'sheep', name: 's', year: 2019},
{animal: 'sheep', name: 'sss', year: 2016},
]
and I would like that the animal column is expandible. How can I do?
I try groupBy by Lodash but obviously it's not the good method here.
const result = [
{animal: 'cat', name: 'mu', year: 2016},
{animal: 'cat', name: 'muji', year: 2021},
{animal: 'cat', name: 'mine', year: 2021},
{animal: 'dog', name: 'fido', year: 2000},
{animal: 'hamster', name: 'gerry', year: 2020},
{animal: 't-rex', name: 'dino', year: 2020},
{animal: 'sheep', name: 's', year: 2019},
{animal: 'sheep', name: 'sss', year: 2016},
].reduce(function (acc, obj) {
const x = acc.findIndex((entity)=>entity.animal===obj.animal);
if(x!== -1){
acc[x].subrows.push(obj)
}else{
const xx= {'animal':obj.animal,subrows:[obj]}
acc.push(xx)
}
return acc;
}, [])
console.log(result)
I have the following type of data assigned to var dataTransformation, which I'm taking from the user in apache superset using metric.
{country: "Afghanistan", region: "South Asia", year: 1960, value: 91.779}
{country: "Afghanistan", region: "South Asia", year: 1961, value: 91.492}
{country: "Afghanistan", region: "South Asia", year: 1962, value: 91.195}
{country: "Bangladesh", region: "South Asia", year: 1960, value: 94.865}
{country: "Bangladesh", region: "South Asia", year: 1961, value: 94.722}
{country: "Bangladesh", region: "South Asia", year: 1962, value: 94.502}
{country: "Canada", region: "North America", year: 1960, value: 30.939}
{country: "Canada", region: "North America", year: 1961, value: 30.332}
{country: "Canada", region: "North America", year: 1962, value: 29.506}
But I want to convert it into the below format. I tried it using the array map function, loops, and string concatenation but it is not efficient. Is there any way to do it in javascript?
{
"South Asia": [
["Afghanistan", 91.779, 91.492, 91.195],
["Bangladesh", 94.865, 94.722, 94.502],
],
"North America":[
["Canada", 30.939, 30.332, 29.506],
],
}
I'm expecting a guide on how to do it, not fully working code.
const data = [{
country: "Afghanistan",
region: "South Asia",
year: 1960,
value: 91.779
},{
country: "Afghanistan",
region: "South Asia",
year: 1961,
value: 91.492
},{
country: "Afghanistan",
region: "South Asia",
year: 1962,
value: 91.195
},{
country: "Bangladesh",
region: "South Asia",
year: 1960,
value: 94.865
},{
country: "Bangladesh",
region: "South Asia",
year: 1961,
value: 94.722
},{
country: "Bangladesh",
region: "South Asia",
year: 1962,
value: 94.502
},{
country: "Canada",
region: "North America",
year: 1960,
value: 30.939
},{
country: "Canada",
region: "North America",
year: 1961,
value: 30.332
},{
country: "Canada",
region: "North America",
year: 1962,
value: 29.506
}];
const res = data.reduce((acc, {country, region, year, value}) => {
acc = {
...acc,
[region]: {
...acc[region],
[country]: !acc?.[region]?.[country] ? [value] : acc[region][country].concat(value)
}
}
return acc;
}, { });
console.log(res);
const data = [
{ country: "Afghanistan", region: "South Asia", year: 1960, value: 91.779 },
{ country: "Afghanistan", region: "South Asia", year: 1961, value: 91.492 },
{ country: "Afghanistan", region: "South Asia", year: 1962, value: 91.195 },
{ country: "Bangladesh", region: "South Asia", year: 1960, value: 94.865 },
{ country: "Bangladesh", region: "South Asia", year: 1961, value: 94.722 },
{ country: "Bangladesh", region: "South Asia", year: 1962, value: 94.502 },
{ country: "Canada", region: "North America", year: 1960, value: 30.939 },
{ country: "Canada", region: "North America", year: 1961, value: 30.332 },
{ country: "Canada", region: "North America", year: 1962, value: 29.506 },
];
const transformation = data.reduce((acc, curr) => {
const { country, region, year, value } = curr;
if (!acc[region]) {
acc[region] = [];
acc[region].push([country, value]);
return acc;
}
let isCountryExist = false;
acc[region].forEach((el) => {
if (el.includes(country)) {
isCountryExist = true;
el.push(value);
}
});
if (!isCountryExist) {
acc[region].push([country, value]);
}
return acc;
}, {});
console.log(transformation);
Assuming that dataTransformation is an Array, the first step should be converting it to an object of regions containing objects with the countries as keys and arrays as values. This would keep the time complexity of this task at the minimum:
const dataTransformation = [
{country: "Afghanistan", region: "South Asia", year: 1960, value: 91.779},
{country: "Afghanistan", region: "South Asia", year: 1961, value: 91.492},
{country: "Afghanistan", region: "South Asia", year: 1962, value: 91.195},
{country: "Bangladesh", region: "South Asia", year: 1960, value: 94.865},
{country: "Bangladesh", region: "South Asia", year: 1961, value: 94.722},
{country: "Bangladesh", region: "South Asia", year: 1962, value: 94.502},
{country: "Canada", region: "North America", year: 1960, value: 30.939},
{country: "Canada", region: "North America", year: 1961, value: 30.332},
{country: "Canada", region: "North America", year: 1962, value: 29.506}
];
const dataTransformationObject = dataTransformation.reduce((o, i) => {
o[i.region] = o[i.region] || {};
o[i.region][i.country] = o[i.region][i.country] || [];
o[i.region][i.country].push(i.value);
return o;
},{});
console.log(dataTransformationObject);
The previous code will return this object:
{
"South Asia": {
"Afghanistan": [
91.779,
91.492,
91.195
],
"Bangladesh": [
94.865,
94.722,
94.502
]
},
"North America": {
"Canada": [
30.939,
30.332,
29.506
]
}
}
And I strongly recommend you to use it directly in this way. Why? because to access to data > region > country, you can do it directly: e.g, data['North America']['Canada'][0] is 30.939. Otherwise you would need to iterate in the array of regions to find a country, and that would not be optimal.
But if you still need the output that you requested in your answer, you can transform the previous object to achieve it:
const dataTransformation = [
{country: "Afghanistan", region: "South Asia", year: 1960, value: 91.779},
{country: "Afghanistan", region: "South Asia", year: 1961, value: 91.492},
{country: "Afghanistan", region: "South Asia", year: 1962, value: 91.195},
{country: "Bangladesh", region: "South Asia", year: 1960, value: 94.865},
{country: "Bangladesh", region: "South Asia", year: 1961, value: 94.722},
{country: "Bangladesh", region: "South Asia", year: 1962, value: 94.502},
{country: "Canada", region: "North America", year: 1960, value: 30.939},
{country: "Canada", region: "North America", year: 1961, value: 30.332},
{country: "Canada", region: "North America", year: 1962, value: 29.506}
];
const dataTransformationObject = dataTransformation.reduce((o, i) => {
o[i.region] = o[i.region] || {};
o[i.region][i.country] = o[i.region][i.country] || [];
o[i.region][i.country].push(i.value);
return o;
},{});
const final = Object.entries(dataTransformationObject).reduce((o, e) => {
o[e[0]] = Object.keys(e[1]).map((c) => [c, ...e[1][c]]);
return o;
}, {});
console.log(final);
Which will give you the desired output:
{
"South Asia": [
[
"Afghanistan",
91.779,
91.492,
91.195
],
[
"Bangladesh",
94.865,
94.722,
94.502
]
],
"North America": [
[
"Canada",
30.939,
30.332,
29.506
]
]
}
I have a json file in the following format:
const data = [
{category: "A", country: "UK", name: "United Kingdom", country_id: "01", 2015: 5, 2016: 56, 2017: 10},
{category: "B", country: "UK", name: "United Kingdom", country_id: "01", 2015: 4, 2016: 10, 2017: 10},
{category: "C", country: "UK", name: "United Kingdom", country_id: "01", 2015: 10, 2016: 7, 2017: 45},
{category: "A", country: "PO", name: "Poland", country_id: "02", 2015: 9, 2016: 14, 2017: 10},
{category: "B", country: "PO", name: "Poland", country_id: "02", 2015: 10, 2016: 40, 2017: 0},
{category: "C", country: "PO", name: "Poland", country_id: "02", 2015: 60, 2016: 30, 2017: 74},
{category: "A", country: "CZ", name: "Czech Republic", country_id: "03", 2015: 30, 2016: 20, 2017: 10},
{category: "B", country: "CZ", name: "Czech Republic", country_id: "03", 2015: 15, 2016: 28, 2017: 1},
{category: "C", country: "CZ", name: "Czech Republic", country_id: "03", 2015: 16, 2016: 10, 2017: 2}
]
and I want to pivot the data to get the following format:
move 2015, 2016 and 2017 into a property named year
create a, b and c properties from category property values that will contain the different values.
have a line/object per country and year and any other ordinal categories I would like to keep.
const data = [
{country: "UK", name: "United Kingdom", country_id: "01", year: "2015", "a": 5 , "b": 4, "c": 10},
{country: "UK", name: "United Kingdom", country_id: "01", year: "2016", "a": 56 , "b": 10, "c": 7},
{country: "UK", name: "United Kingdom", country_id: "01", year: "2017", "a": 10 , "b": 10, "c": 45},
{country: "PO", name: "Poland", country_id: "02", year: "2015", "a": 9 , "b": 10, "c": 80},
{country: "PO", name: "Poland", country_id: "02", year: "2016", "a": 14 , "b": 40, "c": 30},
{country: "PO", name: "Poland", country_id: "02", year: "2017", "a": 10 , "b": 0, "c": 74},
{country: "CZ", name: "Czech Republic", country_id: "03", year: "2015", "a": 30 , "b": 15, "c": 16},
{country: "CZ", name: "Czech Republic", country_id: "03", year: "2016", "a": 20 , "b": 28, "c": 1},
{country: "CZ", name: "Czech Republic", country_id: "03", year: "2017", "a": 10 , "b": 1, "c": 2}
I tried writing a for loop inside a map method but I am unable to create a, b and c properties.
The rotation is done on the 3 lines commented 'Rotation'
To be able to do this we need to be able to access multiple rows of the original dataset. The strategy here builds us up to be able to do that.
Step 1. Get lists of the unique country_ids, years and categories
There are several ways to do this, and I have shown the easiest to understand method, which is to convert to a Set (which automatically removes duplicates) and then back to an Array for convenience of use.
Step 2. Move from a simple array, into an object
Instead of the rows being simply in sequence 0...8, we now have them in a 3x3 grid, addressible by country and category.
Step 3. Construct the desired output
Now within each country, we can extract all the data for a chosen year, by "plucking" the values for this year from the three different categories in the original data.
const data = [
{category: "A", country: "UK", name: "United Kingdom", country_id: "01", 2015: 5, 2016: 56, 2017: 10},
{category: "B", country: "UK", name: "United Kingdom", country_id: "01", 2015: 4, 2016: 10, 2017: 10},
{category: "C", country: "UK", name: "United Kingdom", country_id: "01", 2015: 10, 2016: 7, 2017: 45},
{category: "A", country: "PO", name: "Poland", country_id: "02", 2015: 9, 2016: 14, 2017: 10},
{category: "B", country: "PO", name: "Poland", country_id: "02", 2015: 10, 2016: 40, 2017: 0},
{category: "C", country: "PO", name: "Poland", country_id: "02", 2015: 60, 2016: 30, 2017: 74},
{category: "A", country: "CZ", name: "Czech Republic", country_id: "03", 2015: 30, 2016: 20, 2017: 10},
{category: "B", country: "CZ", name: "Czech Republic", country_id: "03", 2015: 15, 2016: 28, 2017: 1},
{category: "C", country: "CZ", name: "Czech Republic", country_id: "03", 2015: 16, 2016: 10, 2017: 2}
]
// Step 1. Extract the unique country_id, category Ids and years
const country_ids = Array(...new Set(data.map((x) => x.country_id)));
const categories = Array(...new Set(data.map((x) => x.category)));
const years = ["2015","2016","2017"];
// Step 2. Convert the source data into an object so that you can conveniently read off particular rows, in terms of COUNTRY_ID and CATEGORY
const sourceRows = {};
data.forEach((row) => {
if (!sourceRows[row.country_id]) {
sourceRows[row.country_id] = {};
}
sourceRows[row.country_id][row.category] = row;
});
// You can visualise the output here with this, if you want:
// console.log(sourceRows)
// Step 3. Create destination array, and poke a row into it for each country & year.
const destination = [];
country_ids.forEach((country_id) => {
years.forEach((year) => {
const sourceRow = sourceRows[country_id][categories[0]];
const destRow = {
country_id: country_id,
name: sourceRow.name,
country: sourceRow.country,
year: year,
a: sourceRows[country_id]["A"][year], // Rotation
b: sourceRows[country_id]["B"][year], // Rotation
c: sourceRows[country_id]["C"][year] // Rotation
};
destination.push(destRow);
});
});
console.log(destination);
Not the best solution, but this works. At the and, I made a workaround for the duplicates. You could use ...rest parameter to initialize years array if there will be new data for other years.
let newData = [];
let countries = data.map(({country})=> country)
let categories = data.map(({category})=> category)
let years = [2015,2016,2017];
countries.forEach(country => {
let countryData = data.filter(({country:c}) => c==country);
let yearData = {2015:{},2016:{},2017:{}};
years.forEach(year => {
categories.forEach(category => {
yearData[year][category] = countryData.find(({category:cat}) => cat==category)[year]
})
})
let {name,country_id}= data.find(({country:c}) => c == country);
Object.entries(yearData).forEach(([year,categories]) => {
newData.push({country,name,country_id,year, ...categories})
})
newData = newData.filter((data,i) => i%9<3)
console.log(newData)
})
This question already has answers here:
Sorting an array of objects by property values
(35 answers)
Closed 4 years ago.
I have an array of objects that I want to sort first by date and next by its numeric value.
let arr = [
{date: 2018-06-19 12:05:43.232Z, value: 3},
{date: 2018-06-20 12:05:43.232Z, value: 4},
{date: 2018-06-18 12:05:43.232Z, value: 2},
{date: 2018-06-20 12:05:43.232Z, value: 4},
{date: 2018-06-19 12:05:43.232Z, value: 5},
{date: 2018-06-18 12:05:43.232Z, value: 5},
{date: 2018-06-20 12:05:43.232Z, value: 5},
{date: 2018-06-19 12:05:43.232Z, value: 4},
]
I want to sort each index by the date and the value so the result would be :
let arr = [
{date: 2018-06-18 12:05:43.232Z, value: 2},
{date: 2018-06-18 12:05:43.232Z, value: 5},
{date: 2018-06-19 12:05:43.232Z, value: 3},
{date: 2018-06-19 12:05:43.232Z, value: 4},
{date: 2018-06-19 12:05:43.232Z, value: 5},
{date: 2018-06-20 12:05:43.232Z, value: 3},
{date: 2018-06-20 12:05:43.232Z, value: 4},
{date: 2018-06-20 12:05:43.232Z, value: 5},
]
How can it be done?
You can use Array.sort with ||
const res = arr.sort((a, b) => Date.parse(a.date) - Date.parse(b.date) || a.value - b.value);
console.log(res);
<script>
let arr = [{
date: '2018-06-19 12:05:43.232Z',
value: 3
},
{
date: '2018-06-20 12:05:43.232Z',
value: 4
},
{
date: '2018-06-18 12:05:43.232Z',
value: 2
},
{
date: '2018-06-20 12:05:43.232Z',
value: 4
},
{
date: '2018-06-19 12:05:43.232Z',
value: 5
},
{
date: '2018-06-18 12:05:43.232Z',
value: 5
},
{
date: '2018-06-20 12:05:43.232Z',
value: 5
},
{
date: '2018-06-19 12:05:43.232Z',
value: 4
},
]
</script>
Yo can do it using lodash library. If you check the docs of orderBy function you'll see that, it is exactly what you need.
let arr = [
{"date": "2018-06-19 12:05:43.232Z", "value": 3},
{"date": "2018-06-20 12:05:43.232Z", "value": 4},
{"date": "2018-06-18 12:05:43.232Z", "value": 2},
{"date": "2018-06-20 12:05:43.232Z", "value": 4},
{"date": "2018-06-19 12:05:43.232Z", "value": 5},
{"date": "2018-06-18 12:05:43.232Z", "value": 5},
{"date": "2018-06-20 12:05:43.232Z", "value": 5},
{"date": "2018-06-19 12:05:43.232Z", "value": 4}
]
Applying _orderBy on your array as follows:
_.orderBy(arr, ['date', 'value'], ['asc', 'asc']);
will get you the result that you want.
Check the example below:
let arr = [
{"date": "2018-06-19 12:05:43.232Z", "value": 3},
{"date": "2018-06-20 12:05:43.232Z", "value": 4},
{"date": "2018-06-18 12:05:43.232Z", "value": 2},
{"date": "2018-06-20 12:05:43.232Z", "value": 4},
{"date": "2018-06-19 12:05:43.232Z", "value": 5},
{"date": "2018-06-18 12:05:43.232Z", "value": 5},
{"date": "2018-06-20 12:05:43.232Z", "value": 5},
{"date": "2018-06-19 12:05:43.232Z", "value": 4}
]
console.log(_.orderBy(arr, ['date', 'value'], ['asc', 'asc']))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>