Reputation:
I have the following arrays:
const countries = ['Belgium', 'Uk']
const years = ['2019', '2018', '2017']
const colors = ['red', 'orange', 'green']
I want an array like that:
const result = [
{
country: 'Belgium',
year: '2019',
red: random(min, max),
orange: random(min, max),
green: random(min, max),
},
{
country: 'Belgium',
year: '2018',
red: random(min, max),
orange: random(min, max),
green: random(min, max),
},
{
country: 'Belgium',
year: '2017',
red: random(min, max),
orange: random(min, max),
green: random(min, max),
},
{
country: 'Uk',
year: '2019',
red: random(min, max),
orange: random(min, max),
green: random(min, max),
},
{
country: 'Uk',
year: '2018',
red: random(min, max),
orange: random(min, max),
green: random(min, max),
},
{
country: 'Uk',
year: '2017',
red: random(min, max),
orange: random(min, max),
green: random(min, max),
},
{
country: 'Tot',
year: '2019',
red: // sum of the values of the red key for each country in the year 2019,
orange: // sum of the values of the orange key for each country in the year 2019,
green: // sum of the values of the green key for each country in the year 2019,
},
{
country: 'Tot',
year: '2018',
red: // sum of the values of the red key for each country in the year 2018,
orange: // sum of the values of the orange key for each country in the year 2018,
green: // sum of the values of the green key for each country in the year 2018,
},
{
country: 'Tot',
year: '2017',
red: // sum of the values of the red key for each country in the year 2017,
orange: // sum of the values of the orange key for each country in the year 2017,
green: // sum of the values of the green key for each country in the year 2017,
},
]
So, for each year, and for each country, there must be an object containing the keys of each color. The value must be random.
Then, should be other objects with country = Total
and with values of colors key the sum of the values of other objects.
This is what I'm trying to do:
function createValues() {
const min = 0
const max = 300
const dataset: any = []
countries.forEach(country => {years.forEach(year => {colors.forEach(color => {dataset.push({country: country, year: year, [color]: random(min, max),})})})})}
But it doesn't work and I don't know how to compute the sum values.
Upvotes: 3
Views: 332
Reputation: 1250
const countries = ['Belgium', 'Uk']
const years = ['2019', '2018', '2017']
const colors = ['red', 'orange', 'green']
countries.push('Total');
result = [];
function random(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
countries.forEach(item => {
if (item !== 'Total') {
yearArr = [];
years.forEach(y => {
obj = {
country: item,
year: y
}
colors.forEach(c => {
obj[c] = random(0, 300)
})
result.push(obj)
yearArr.push(obj)
})
}
})
years.forEach(y => {
obj = result.filter(({ year, country }) => (year === y && country
!== 'total'))
.reduce((a, b) => ({ country: 'total', year: a.year, red: a.red +
b.red, orange: a.orange + b.orange, green: a.green + b.green }))
result.push(obj)
})
console.log(result);
Upvotes: 2
Reputation: 386604
You could get a cartesian result of countries and years, get all totals and build the missing total objects.
function getCartesian(object) {
return Object.entries(object).reduce((r, [k, v]) => {
var temp = [];
r.forEach(s =>
(Array.isArray(v) ? v : [v]).forEach(w =>
(w && typeof w === 'object' ? getCartesian(w) : [w]).forEach(x =>
temp.push(Object.assign({}, s, { [k]: x }))
)
)
);
return temp;
}, [{}]);
}
function random(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
const
countries = ['Belgium', 'Uk'],
years = ['2019', '2018', '2017'],
colors = ['red', 'orange', 'green'],
result = getCartesian({ country: countries, year: years })
.map(o => Object.assign(o, ...colors.map(k => ({ [k]: random(0, 300) })))),
totals = result.reduce((r, o) => (colors.forEach(color => {
r[o.year] = r[o.year] || {};
r[o.year][color] = (r[o.year][color] || 0) + o[color];
}), r), {});
result.push(...years.map(year => Object.assign(
{ country: 'TOT', year },
...colors.map(color => ({ [color]: totals[year][color] }))
)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 3
Reputation: 64923
Here's a purely functional solution. It uses local mutation in Array#reduce
, but the computation itself is pure:
const ap = fs => xs => xs.flatMap (x => fs.map (f => f (x)))
const lift2 = f => xs => ys => ap (xs.map (f)) (ys)
// source: https://stackoverflow.com/a/1527820/411632
const random = min => max => {
const min_ = Math.ceil (min)
const max_ = Math.floor (max)
return Math.floor (Math.random () * (max - min + 1)) + min
}
//////////////////////////////////////////////////////////////
const countries = ['Belgium', 'Uk']
const years = ['2019', '2018', '2017']
const output1 = lift2 (year => country => ({
country,
year,
red: random (1) (255),
orange: random (1) (255),
green: random (1) (255)
})) (years) (countries)
const output2 = Object.values (
output1.reduce ((o, { year, red, green, orange, ...rest }) => {
const {
red:red_ = 0,
green:green_ = 0,
orange:orange_ = 0
} = o[year] || {}
o[year] = {
...rest,
country: 'Tot',
year,
red: red + red_,
green: green + green_,
orange: orange + orange_
}
return o
}, {})
)
const output3 = [...output1, ...output2]
console.log (output3)
Upvotes: 0
Reputation: 23515
Double reduce and spread operator.
For each country and then for each years, we are creating a new json. This json is made of the country + year key and colors we have to loop on aswell. Then we add the total.
function random(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
const countries = ['Belgium', 'Uk'];
const years = ['2019', '2018', '2017'];
const colors = ['red', 'orange', 'green'];
const arr = countries.reduce((tmp, x) => [
...tmp,
...years.map(y => colors.reduce((json, z) => {
json[z] = random(0, 255);
return json;
}, {
country: x,
year: y,
})),
], []);
// add the Tot
const arrWithTotal = [
...arr,
...years.map(y => colors.reduce((json, x) => {
json[x] = arr.reduce((tmp, z) => z.year === y ? tmp + z[x] : tmp, 0);
return json;
}, {
country: 'Tot',
year: y,
})),
];
console.log(arrWithTotal);
Upvotes: 0
Reputation: 35222
You could do something like this using forEach
and reduce
combo
reduce
the combo and get the sum for each color grouped based on the yearconcat
the combo
array and total values grouped from the reduce
const countries = ['Belgium', 'Uk']
const years = ['2019', '2018', '2017']
const colors = ['red', 'orange', 'green']
function random(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
const combo = [];
countries.forEach(country => {
years.forEach(year => {
const obj = {country,year};
colors.forEach(color => {
obj[color] = random(1, 10)
})
combo.push(obj)
})
})
const total = combo.reduce((acc, {year, country,...rest}) => {
acc[year] = acc[year] || {year,country: 'Tot'};
for (let color in rest) {
acc[year][color] = (acc[year][color] + rest[color]) || rest[color]
}
return acc;
}, {})
const final = combo.concat(Object.values(total))
console.log(final)
Upvotes: 2
Reputation: 704
My solution
const countries = ['Belgium', 'Uk'];
const years = ['2019', '2018', '2017'];
const colors = ['red', 'orange', 'green'];
const min = 0;
const max = 300;
console.log(getTotal(
getResult(countries, years, colors),
colors
));
function getResult(countries, years, colors) {
const result = [];
countries.forEach(country => {
years.forEach(year => {
const item = {
country: country,
year: year
};
colors.forEach(color => {
item[color] = random(min, max);
});
result.push(item);
});
});
return result;
}
function getTotal(data, colors) {
const total = {};
data.forEach(item => {
if (typeof total[item.year] === 'undefined') {
total[item.year] = {};
colors.forEach(color => {
total[item.year][color] = item[color];
});
} else {
colors.forEach(color => {
total[item.year][color] += item[color];
});
}
});
for (var totalItem in total) {
data.push({country: 'Tot', year: totalItem, ...total[totalItem]});
}
return data;
}
function random(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
Upvotes: 0
Reputation: 161
This is how it works:
const countries = ['Belgium', 'Uk']
const years = ['2019', '2018', '2017']
const colors = ['red', 'orange', 'green']
const dataset = [];
countries.forEach((country)=>{
years.forEach((year)=>{
const obj = {
country: country,
year: year
}
colors.forEach((color)=>{
obj[color] = Math.floor(Math.random() * 300) + 1;
})
dataset.push(obj);
})
})
console.log(dataset);
https://jsfiddle.net/martinmakesitwork/0x1may62/9/
Upvotes: 0