1

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!

3
  • Can you post expected result? Commented Jun 16, 2016 at 13:40
  • @NenadVracar for [question1][org2] = 47.66 and [question2][org2] = 43.66 Commented Jun 16, 2016 at 13:45
  • where should the result go? basically you get 6 averages. Commented Jun 16, 2016 at 13:49

3 Answers 3

1

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);

});
Sign up to request clarification or add additional context in comments.

2 Comments

Hi, I think this is close to what I'm after, but this adds all 6 numbers together and divides by 3, I'm looking to retrieve two separate arrays, with 3 values each. So, the initial sort will return [50, 83, 10] and [95, 21, 15] and then in the sum [143][131] and the avg [47.66][43.66]. Sorry, I don't think I explained it well enough in the question
Yeah, you didn't explain that (and your code isn't trying to do that)
1

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)
}

2 Comments

Hi, this is a really good answer! It gave me a dilemma for which answer to tick, I went with forgivenson's just because he loaded the data in the same way / original post was first, but thanks a lot for the solution!
Well damn.. I should've posted an incorrect solution first! (Just kidding, my answers are 'community wiki' for a reason) ;-)
0

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);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.