Reputation: 1310
Below is the layout of my JSON File.
{
"questions": ["Question1", "Question2"],
"orgs": ["Org1", "Org2", "Org3"],
"dates": ["Q1", "Q2", "Q3"],
"values": [
[
[5, 88, 18],
[50, 83, 10],
[29, 78, 80]
],
[
[46, 51, 61],
[95, 21, 15],
[49, 86, 43]
]
]
}
I'm trying to retrieve a single array of values by looping through each question, indexed by an "orgs" value and then adding each value retrieved and dividing it by data.dates.length.
Here is my code;
d3.json("data.json", function(error, data) {
var array = new Array()
var orgS = "Org2"
var org = data.orgs.indexOf(orgS);
for (var question = 0; question < data.questions.length; question++) {
array.push(
data.values[question][org]
)
console.log(array)
}
// add array together
array.reduce(function(a, b) {
return a + b;
})
// calculate average
var avg = array / data.dates.length;
})
Here is a plnk;
http://plnkr.co/edit/wMv8GmkD1ynjo9WZVlMb?p=preview
I think the issue here is how I'm retrieving the values in the first place? as at the moment, although I am retrieving the correct values in the console log, I'm getting the array twice, and both times inside nested arrays. I'm not so sure how to remedy the problem?
For reference;
[question1][org1] corresponds to the values [5, 88, 18].
Hope someone can offer some advice here?
Thanks!
Upvotes: 1
Views: 61
Reputation: 386522
You need to store the sum, the result of reduce.
// add array together
// store in sum
var sum = array.reduce(function(a, b) {
return a + b;
}, 0); // use 0 as start value
For the average, you do not need the length of data.dates
but from array, because you collecting the values and this length is important.
// calculate average
var avg = sum / array.length;
Together for all values, you might get this
var data = { "questions": ["Question1", "Question2"], "orgs": ["Org1", "Org2", "Org3"], "dates": ["Q1", "Q2", "Q3"], "values": [[[5, 88, 18], [50, 83, 10], [29, 78, 80]], [[46, 51, 61], [95, 21, 15], [49, 86, 43]]] },
sum = [];
data.values.forEach(function (a, i) {
sum[i] = sum[i] || [];
a.forEach(function (b) {
b.forEach(function (c, j) {
sum[i][j] = sum[i][j] || 0;
sum[i][j] += c;
});
});
});
data.avg = sum.map(function (a, i) {
return a.map(function (b) {
return b / data.values[i].length;
});
});
console.log(sum);
console.log(data);
Upvotes: 0
Reputation: 4435
Since you clarified your question to indicate you want to calculate separate averages for each question, I've rewritten my answer. You should do all the calculations in the for loop, since the loop is looping through the questions. Then store your averages in an array.
d3.json("data.json", function(error, data) {
var averages = new Array()
var orgS = "Org2"
var org = data.orgs.indexOf(orgS);
var values, sum;
for (var question = 0; question < data.questions.length; question++) {
// get the values for the question/org
values = data.values[question][org];
// calculate the sum
sum = values.reduce(function(a, b) {
return a + b;
});
// calculate the average
averages.push(sum / values.length);
}
console.log(averages);
});
Upvotes: 1
Reputation:
Perform the .reduce()
in the for
loop and push that result into array
. That will give you the an array of the results you expected.
array.push(data.values[question][org].reduce(function(a, b) {
return a + b
}, 0) / data.dates.length)
[
47.666666666666664,
43.666666666666664
]
Currently, you're attempting to perform addition on the arrays themselves in the .reduce()
callback instead of reducing the members of each individual array to their sum, and then average.
Demo: (Click the text below to show the whole function)
var data = {
"questions": ["Question1", "Question2"],
"orgs": ["Org1", "Org2", "Org3"],
"dates": ["Q1", "Q2", "Q3"],
"values": [
[
[5, 88, 18],
[50, 83, 10],
[29, 78, 80]
],
[
[46, 51, 61],
[95, 21, 15],
[49, 86, 43]
]
]
}
x(data)
// Your callback function.
function x(data) {
var array = new Array()
var orgS = "Org2"
var org = data.orgs.indexOf(orgS);
for (var question = 0; question < data.questions.length; question++) {
array.push(data.values[question][org].reduce(function(a, b) {
return a + b
}, 0) / data.dates.length)
}
console.log(array)
}
Instead of a for
loop, you could also use .map()
.
var array = data.questions.map(function(_, question) {
return data.values[question][org].reduce(function(a, b) {
return a + b
}, 0) / data.dates.length
})
Demo: (Click the text below to show the whole function)
var data = {
"questions": ["Question1", "Question2"],
"orgs": ["Org1", "Org2", "Org3"],
"dates": ["Q1", "Q2", "Q3"],
"values": [
[
[5, 88, 18],
[50, 83, 10],
[29, 78, 80]
],
[
[46, 51, 61],
[95, 21, 15],
[49, 86, 43]
]
]
}
x(data)
// Your callback function.
function x(data) {
var orgS = "Org2"
var org = data.orgs.indexOf(orgS);
var array = data.questions.map(function(_, question) {
return data.values[question][org].reduce(function(a, b) {
return a + b
}, 0) / data.dates.length
})
console.log(array)
}
Upvotes: 1