1

I have a json object as below:

{
    "critiquesAvg": 4.75: , 
    "critiques":[
        {
            'author': 'John Does',
            'comment': "I like it",
            'stars' : 5
        },
        {
            'author': 'Jacob Works',
            'comment': "I like it too",
            'stars' : 4.5
        }
    ]
}

I need to calculate the value (4.75) of critiquesAvg dynamically by averaging the stars property value of the critiques array.

Could somebody help me with it?

EDIT: Apologies, the actually issue I was having was like below:

var dealers = [{
    "id", 1874
    "critiquesAvg": 4.75 ,
    "critiques":[
        {
            'author': 'John Does',
            'comment': "I like it",
            'stars' : 5
        },
        {
            'author': 'Jacob Works',
            'comment': "I like it too",
            'stars' : 4.5
        }
    ]
},
{
    "id": 1345,
    "critiquesAvg": 5 ,
    "critiques":[
        {
            'author': 'John Does',
            'comment': "I like it",
            'stars' : 5
        },
        {
            'author': 'Jacob Works',
            'comment': "I like it too",
            'stars' : 5
        }
    ]
}
];

and here I wanted to calculate the values of the critiquesAvg property dynamically based on the number of average of the critiques for a particular dealer's data.

3
  • 1
    What about redefining property critiquesAvg using Object.defineProperty function? Commented Aug 25, 2014 at 7:08
  • I didn't get what you want, can you give an example? Commented Aug 25, 2014 at 7:08
  • @Mritunjay: Just wanted to get the value 4.75 for critiquesAvg as data.critiquesAvg, having critiquesAvg calculated dynamically based on the number of critique objects in the critiques array. Commented Aug 25, 2014 at 7:35

4 Answers 4

3

I would use reduce for this (fiddle here):

var data = {
    "critiquesAvg": 4.75, 
    "critiques":[
        {
            'author': 'John Does',
            'comment': "I like it",
            'stars' : 5
        },
        {
            'author': 'Jacob Works',
            'comment': "I like it too",
            'stars' : 4.5
        }
    ]
};

var sum = data.critiques.reduce(function(x, y) { return x.stars + y.stars });
var average = sum / data.critiques.length;

data.critiquesAvg = average;

As for the updated question, you need to add an extra loop, for example using forEach (updated fiddle here):

dealers.forEach(function(data) {
    var sum = data.critiques.reduce(function(x, y) { return x.stars + y.stars });
    var average = sum / data.critiques.length;

    data.critiquesAvg = average;
});
Sign up to request clarification or add additional context in comments.

2 Comments

Hello Robby thanks for you reply, I've edited my question a bit, could you please have a look at it again and see if there could be a solution for that? Thank you.
@JyotiPuri Chrome (yes), Firefox (since 1.5), IE (since 9), Safari (yes), Opera (yes). What browser were you planning on using?
2

You can do this by replacing critiquesAvg by a function like:

critiquesAvg: function(){
    var stars = 0;
    for(i=0;i<this.critiques.length;i++) {
        stars +=this.critiques[i].stars;
    }
    return stars/this.critiques.length
}, 

Check script.js this plunker: http://plnkr.co/edit/dDxkZxKxvq0HRppASnzR?p=preview

2 Comments

@Jyoti: I've just modified the original question a bit. Could you please have a look at the edited part of it? Thanks.
This no longer qualifies as JSON.
1

Add a init function to your object ,and do all your calculations inside of it. if you look at other object oriented languages, usually you do this sort of calculations in your constructor.similarly you can achieve the same with a custom method,which would act as a constructor and will set up the initial state of your object.

var obj = ({
  "critiquesAvg": 0, //start with zero and init function will calculate the actual avg
  "critiques": [{
    'author': 'John Does',
    'comment': "I like it",
    'stars': 5
  }, {
    'author': 'Jacob Works',
    'comment': "I like it too",
    'stars': 4.5
  }],
  init: function() {
    var result = this.critiques.reduce(function(prev, current, idx, arr) {
      return prev['stars'] + current['stars'];
    });
    this.critiquesAvg = result / this.critiques.length;
    return this;
  }
}).init(); // you are invoking the init method inline here (coding pattern)
           // also watch out for the ( ) around the object literal. 
           // this is what makes the method on the object invokable inline.

This is sort of a coding pattern, usually followed to set object states(especially when you using the object literal syntax in javascript).

DEMO

Updated answer

follows the same pattern, but instead of having a init method for each, a common initialize method would do the same operation.

var initialize = function() {
  var result = this.critiques.reduce(function(prev, current, idx, arr) {
    return prev['stars'] + current['stars'];
  });
  this.critiquesAvg = result / this.critiques.length;
  return this;
};

var dealers = [({
  "id": 1874,
  "critiquesAvg": 0,
  "critiques": [{
    'author': 'John Does',
    'comment': "I like it",
    'stars': 5
  }, {
    'author': 'Jacob Works',
    'comment': "I like it too",
    'stars': 4.5
  }],
  init: initialize
}).init(), ({
  "id": 1345,
  "critiquesAvg": 0,
  "critiques": [{
    'author': 'John Does',
    'comment': "I like it",
    'stars': 5
  }, {
    'author': 'Jacob Works',
    'comment': "I like it too",
    'stars': 5
  }],
  init: initialize
}).init()];

DEMO

2 Comments

Thank you for it, really good stuff. Could I ask you to have a look at the edited part of the question again and see if there is a DRY solution for it.
Thanks BOSS, really clean stuff :)
1

Robby did it, I thought I would extend it to a function

function dataGen(data){
    //so we do not overwrite data globally as objects are references
    var data = data;
    var sum = data.critiques.reduce(function(x, y) {
        return x.stars + y.stars 
    });
    var average = sum / data.critiques.length;

    data.critiquesAvg = average;
    return data;
}

var data = { 
    "critiques":[
        {
            'author': 'John Does',
            'comment': "I like it",
            'stars' : 5
        },
        {
            'author': 'Jacob Works',
            'comment': "I like it too",
            'stars' : 4.5
        }
    ]
};

data.critiques.push({
    'author': 'Wacob Works',
    'comment': "I like it too",
    'stars' : 3.5
});

data = dataGen(data);

ok great updated to your requirements, hope this helps http://jsbin.com/sevor/1/edit

var dealers = [{
  "id": 1874,
    "critiquesAvg": 0 ,
    "critiques":[
        {
            'author': 'John Does',
            'comment': "I like it",
            'stars' : 5
        },
        {
            'author': 'Jacob Works',
            'comment': "I like it too",
            'stars' : 4.5
        }
    ]
},
{
    "id": 1345,
    "critiquesAvg": 5 ,
    "critiques":[
        {
            'author': 'John Does',
            'comment': "I like it",
            'stars' : 5
        },
        {
            'author': 'Jacob Works',
            'comment': "I like it too",
            'stars' : 5
        }
    ]
}
];

var Dealers = {
    calculate: function(dealer){
        var sum = dealer.critiques.reduce(function(x, y) {
            return x.stars + y.stars; 
        });
        var average = sum / dealer.critiques.length;
        return average;
    },
    gen: function(dealers){
        for(i=0;i<dealers.length;i++){
            dealers[i].critiquesAvg = this.calculate(dealers[i]);
        }

        return dealers;
    }
};

dealers = Dealers.gen(dealers);

dealers.push({
    "id": 1346,
    "critiquesAvg": 0 ,
    "critiques":[
        {
            'author': 'John Does',
            'comment': "I like it",
            'stars' : 5
        },
        {
            'author': 'Jacob Works',
            'comment': "I like it too",
            'stars' : 5
        }
    ]
});

dealers = Dealers.gen(dealers);
console.log(dealers);

1 Comment

Could you have a look at the edited part of the question again and see if there is solution for it? Whe I get the json data of dealers, I want the critiqueAvg value to be automatically geneted based on the critiques for a particular dealer. Thanks.

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.