Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assign ranks to objects by values in an array of objects

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 comparing 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 complex 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.

like image 956
Rutwick Gangurde Avatar asked Jan 12 '16 13:01

Rutwick Gangurde


People also ask

How do you rank an element in an array?

All elements are ranked from 1 to N in ascending order if they are distinct. If there are say x repeated elements of a particular value then each element should be assigned a rank equal to the arithmetic mean of x consecutive ranks.

How do you assign an object to an array of objects?

assign() method to convert an array to an object, e.g. const obj = Object. assign({}, arr) . The Object. assign method takes a target and source objects as parameters, applies the properties from the sources to the target and returns the result.

How do you reorder an array of objects?

To sort an array of objects in JavaScript, use the sort() method with a compare function. A compare function helps us to write our logic in the sorting of the array of objects. They allow us to sort arrays of objects by strings, integers, dates, or any other custom property.

Can we sort array of objects?

Sorting array of objectsArrays of objects can be sorted by comparing the value of one of their properties.


1 Answers

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

like image 52
Venugopal Avatar answered Oct 25 '22 21:10

Venugopal