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.
this is how I achieved it.
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;
});
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
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