Reputation: 1186
I have an array of nested objects containing values like GDP, income, population etc. per year per state:
// The "records" array looks like this:
[
{
name : "...",
income : [
[1995, 1234], // [year, value]
[1996. 1235],
[...]
],
GDP : [
[1995, 1234],
[1996. 1235],
[...]
],
population : [
[1995, 1234],
[1996. 1235],
[...]
]
}, {
name : "...",
income : [
[...]
],
GDP : [
[...]
],
population : [
[...]
]
}, {
...
}
]
Now, I want to find the minimum and maximum (extent) for each dimension over all states and years.
populationExtents = [659651, 82536680];
gdpExtents = [14250, 2498800];
incomeExtents = [..., ...];
How can I do this without having to traverse the whole array multiple times? Currently, I'm doing this for each dimension:
var income = records.map(function(d, i) {
return d.income;
});
var min = d3.min(income, function(d, i) {
return d3.min(d, function(e) {
return e[1]; // returns values of each year
});
});
var max = d3.max(income, function(d, i) {
return d3.max(d, function(e) {
return e[1];
});
});
But I think this is way too complex, since I should be able to calculate all "local" minimums per dimension and state, and then calculate the global minimum over all states in just on pass (instead of one pass per each dimension).
I tried several levels of d3.map and nested d3.min, but am not able to wrap my head around this structure.
Upvotes: 1
Views: 1380
Reputation: 47119
function getMaxMin( prop ) {
var concat = [].concat,
arr = concat.apply([], records.map(function(value) {
return concat.apply([], value[prop]);
}));
return [ Math.min.apply(Math.min, arr), Math.max.apply(Math.max, arr) ];
}
Or a little prettier:
function getMaxMin( prop ) {
var arr = [];
records.map(function(value) {
arr = arr.concat.apply(arr, value[prop][1]);
});
return [ Math.min.apply(Math.min, arr), Math.max.apply(Math.max, arr) ];
}
EDIT: To exclude year [year, value]
and putting almost everything under the same loop:
function getMaxMin() {
var arrs = [];
records.map(function(value) {
arrs[0] = arrs[0].concat(value.income);
arrs[1] = arrs[1].concat(value.GDP);
arrs[2] = arrs[2].concat(value.population);
});
arrs[0] = arrs[0].filter(c);
arrs[1] = arrs[1].filter(c);
arrs[2] = arrs[2].filter(c);
function c(value, key) {
return key % 2;
}
return [
[ Math.min.apply(Math.min, arrs[0]), Math.max.apply(Math.max, arrs[0]) ],
[ Math.min.apply(Math.min, arrs[1]), Math.max.apply(Math.max, arrs[1]) ],
[ Math.min.apply(Math.min, arrs[2]), Math.max.apply(Math.max, arrs[2]) ]
];
}
var maxMin = getMaxMin();
maxMin === [
[income-min, income-max],
[GDP-min, GDP-max],
[population-min, population-max]
]
Demo: http://jsbin.com/ecineg/1/embed?javascript,console
Upvotes: 3
Reputation: 1835
You can use JavaScript's Math.max
and Math.min
functions with apply
to get the max and min of an array. To get the arrays I am using reduce
and concating the property of each record
var allValues = function (property) {
return records.reduce(function (memo, record) {
return memo.concat(record[property])
}, [])
}
var allIncome = allValues('income')
Math.max.apply(null, allIncome)
Math.min.apply(null, allIncome)
Upvotes: 0