最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Assign ranks to objects by values in an array of objects - Stack Overflow

programmeradmin0浏览0评论

I have an array of objects like so:

var data = {
    a: [
        { keyone:'c', keytwo: 'anna', keythree: 21, keyfour: 15 },
        { keyone:'a', keytwo: 'anna', keythree: 22, keyfour: 15 },
        { keyone:'s', keytwo: 'anna', keythree: 10, keyfour: 15 },
        { keyone:'v', keytwo: 'anna', keythree: 7, keyfour: 15 }
    ],

    b: [
        { keyone:'f', keytwo: 'any', keythree: 45, keyfour: 100 },
        { keyone:'b', keytwo: 'any', keythree: 146, keyfour: 100 },
        { keyone:'t', keytwo: 'any', keythree: 23, keyfour: 100 },
        { keyone:'h', keytwo: 'any', keythree: 11, keyfour: 100 }
    ]
  };

I want to assign ranks to each object, based on values of keythree and keyfour, within the groups as well as within the entire data set. How would I do it?

Update: I have depicted the ranks in my code above.

Resultant object:

var data = {
    a: [
        { keyone:'c', keytwo: 'anna', keythree: 21, keyfour: 15, rankgroup: 3, rankall: 4 },

        { keyone:'a', keytwo: 'anna', keythree: 22, keyfour: 15, rankgroup: 4, rankall: 5 },

        { keyone:'s', keytwo: 'anna', keythree: 22, keyfour: 15, rankgroup: 2, rankall: 2 },

        { keyone:'v', keytwo: 'anna', keythree: 7, keyfour: 15, rankgroup: 1, rankall: 1 }
    ],

    b: [
        { keyone:'f', keytwo: 'any', keythree: 45, keyfour: 100 },

        { keyone:'b', keytwo: 'any', keythree: 146, keyfour: 100 },

        { keyone:'t', keytwo: 'any', keythree: 23, keyfour: 100 },

        { keyone:'h', keytwo: 'any', keythree: 11, keyfour: 100 }
    ]
};

I am using lodash. My idea is to first sort the array based on those keys, then loop over the original object, insert the sorted index by paring another key. This is what I have tried:

var keys = Object.keys(data);
var result = {};
var numkeys;
for(var i=0; i < keys.length; i++) {
    if(!numkeys) {
        var numkeys = _.keys(_.pick(data[keys[i]][0], _.isNumber));
  }

        for(var j=0;j<numkeys.length;j++) {
    var sorted = _.sortBy(data['a'], numkeys[j]);
        _.forEach(sorted, function(n, k) {

        //THIS FAILS
        var t = _.set(_.where(data[keys[i]], {keyone: n.keyone}), keys[i]+'rank', k);
        console.log(t);
        });

    }
  }

How would I do it? My logic seems too plex and the set method does not update the original object by key but adds a new entry after the main object.

Update: Notice the duplicate occurrence of 22 for the object a. This leads to an issue when assigning ranks, since indexOf will always return the index of the first occurrence, hence the second occurrence will never have an index assigned to it and hence the value will be undefined.

I have an array of objects like so:

var data = {
    a: [
        { keyone:'c', keytwo: 'anna', keythree: 21, keyfour: 15 },
        { keyone:'a', keytwo: 'anna', keythree: 22, keyfour: 15 },
        { keyone:'s', keytwo: 'anna', keythree: 10, keyfour: 15 },
        { keyone:'v', keytwo: 'anna', keythree: 7, keyfour: 15 }
    ],

    b: [
        { keyone:'f', keytwo: 'any', keythree: 45, keyfour: 100 },
        { keyone:'b', keytwo: 'any', keythree: 146, keyfour: 100 },
        { keyone:'t', keytwo: 'any', keythree: 23, keyfour: 100 },
        { keyone:'h', keytwo: 'any', keythree: 11, keyfour: 100 }
    ]
  };

I want to assign ranks to each object, based on values of keythree and keyfour, within the groups as well as within the entire data set. How would I do it?

Update: I have depicted the ranks in my code above.

Resultant object:

var data = {
    a: [
        { keyone:'c', keytwo: 'anna', keythree: 21, keyfour: 15, rankgroup: 3, rankall: 4 },

        { keyone:'a', keytwo: 'anna', keythree: 22, keyfour: 15, rankgroup: 4, rankall: 5 },

        { keyone:'s', keytwo: 'anna', keythree: 22, keyfour: 15, rankgroup: 2, rankall: 2 },

        { keyone:'v', keytwo: 'anna', keythree: 7, keyfour: 15, rankgroup: 1, rankall: 1 }
    ],

    b: [
        { keyone:'f', keytwo: 'any', keythree: 45, keyfour: 100 },

        { keyone:'b', keytwo: 'any', keythree: 146, keyfour: 100 },

        { keyone:'t', keytwo: 'any', keythree: 23, keyfour: 100 },

        { keyone:'h', keytwo: 'any', keythree: 11, keyfour: 100 }
    ]
};

I am using lodash. My idea is to first sort the array based on those keys, then loop over the original object, insert the sorted index by paring another key. This is what I have tried:

var keys = Object.keys(data);
var result = {};
var numkeys;
for(var i=0; i < keys.length; i++) {
    if(!numkeys) {
        var numkeys = _.keys(_.pick(data[keys[i]][0], _.isNumber));
  }

        for(var j=0;j<numkeys.length;j++) {
    var sorted = _.sortBy(data['a'], numkeys[j]);
        _.forEach(sorted, function(n, k) {

        //THIS FAILS
        var t = _.set(_.where(data[keys[i]], {keyone: n.keyone}), keys[i]+'rank', k);
        console.log(t);
        });

    }
  }

How would I do it? My logic seems too plex and the set method does not update the original object by key but adds a new entry after the main object.

Update: Notice the duplicate occurrence of 22 for the object a. This leads to an issue when assigning ranks, since indexOf will always return the index of the first occurrence, hence the second occurrence will never have an index assigned to it and hence the value will be undefined.

Share Improve this question edited Jan 19, 2016 at 11:00 Rutwick Gangurde asked Jan 12, 2016 at 13:36 Rutwick GangurdeRutwick Gangurde 4,93212 gold badges55 silver badges91 bronze badges 4
  • what do you mean with as within the entire data set? do you mean a and b or within a and b? – Nina Scholz Commented Jan 12, 2016 at 13:46
  • The ranking should be done for each subarray, meaning a and be, and it should be done w.r.t. to the entire list of array of objects. I'll update my description to add this fact. – Rutwick Gangurde Commented Jan 12, 2016 at 13:55
  • please add an example of the sorted array. – Nina Scholz Commented Jan 12, 2016 at 14:03
  • I don't want to sort it, sorting will make me lose the original indexes. I want to calculate the ranks. I will post a resultant array with the ranks. – Rutwick Gangurde Commented Jan 12, 2016 at 14:07
Add a ment  | 

2 Answers 2

Reset to default 2

this is how I achieved it.

  1. collect all keythree into an array and sort them (to assign rankall based on index).

    var all = [];
    _.forEach(data, function (a, key) {
        _.forEach(a, function(n, k){
        all.push(n.keythree);
      });
    });
    all.sort(function(a,b){
        return a-b;
    });
    
  2. assign ranks

    _.forEach(data, function (a, key) {
        var sorted = _.sortBy(a, 'keythree');
        _.forEach(sorted, function(n, k) {
          var index = _.findIndex(data[key], {keyone: n.keyone});
          data[key][index]['rankgroup'] = k+1;
          data[key][index]['rankall'] = all.indexOf(n.keythree)+1;
        });
    });
    

check this fiddle


EDIT

i'm creating another array for dupes

_.forEach(a, function(n, k) {
    if (all.indexOf(n.keythree) !== -1) {
        dupes.push(n.keythree);
    }
    all.push(n.keythree);
});

and for getting the global rank for these dupe items

    function getGlobalRank(n) {
    var val = n.keythree;
    if (sorted_dupes[val] === undefined) {
        sorted_dupes[val] = [];
        _.forEach(data, function(a, key) {
            _.forEach(_.where(a, {
                keythree: val
            }), function(b) {
                sorted_dupes[val].push(b);
            });
        });
        sorted_dupes[val] = _.sortByAll(sorted_dupes[val], ['keyfour', 'keytwo', 'keyone']);
    }
    return _.findIndex(sorted_dupes[val], {
        keyone: n.keyone,
        keytwo: n.keytwo,
        keythree: n.keythree,
        keyfour: n.keyfour
    }) + 1 + all.indexOf(val);
}

see that the items are sorted based on all the properties in the order keythree, keyfour, keytwo, keyone (you can change the order inside _.sortByAll if you want to)

the code looking uglier than i thought. will update the refactored code soon

check the fiddle

Just in plain Javascript:

For ranking, the data must be sorted, somehow.

This solution features an array with objects and the references to the given objects in data. Then all items are sorted and the original data gets their rankgroup and rankall property.

Edit: Now with same rank for duplicates.

var data = { a: [{ keyone: 'g', keytwo: 'tina', keythree: 21, keyfour: 15 }, { keyone: 'c', keytwo: 'anna', keythree: 21, keyfour: 15 }, { keyone: 'a', keytwo: 'anna', keythree: 22, keyfour: 15 }, { keyone: 's', keytwo: 'anna', keythree: 10, keyfour: 15 }, { keyone: 'v', keytwo: 'anna', keythree: 7, keyfour: 15 }], b: [{ keyone: 'f', keytwo: 'any', keythree: 45, keyfour: 100 }, { keyone: 'b', keytwo: 'any', keythree: 146, keyfour: 100 }, { keyone: 't', keytwo: 'any', keythree: 23, keyfour: 100 }, { keyone: 'h', keytwo: 'any', keythree: 11, keyfour: 100 }] },
    group = {};

Object.keys(data).reduce(function (r, k) {
    return r.concat(data[k].map(function (a) {
        return { obj: k, ref: a };
    }));
}, []).sort(function (a, b) {
    return a.ref.keythree - b.ref.keythree || a.ref.keyfour - b.ref.keyfour;
}).forEach(function (a, i, aa) {
    if (i && a.ref.keythree === aa[i - 1].ref.keythree && a.ref.keyfour === aa[i - 1].ref.keyfour) {
        a.ref.rankgroup = group[a.obj];
        a.ref.rankall = group.rankall;
    } else {
        group[a.obj] = (group[a.obj] || 0) + 1;
        group.rankall = (group.rankall || 0) + 1;
        a.ref.rankgroup = group[a.obj];
        a.ref.rankall = group.rankall;
    }
});

document.write('<pre>' + JSON.stringify(data, 0, 4) + '</pre>');

发布评论

评论列表(0)

  1. 暂无评论