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.
-
what do you mean with as within the entire data set? do you mean
a
andb
or withina
andb
? – 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
2 Answers
Reset to default 2this is how I achieved it.
collect all
keythree
into an array and sort them (to assignrankall
based onindex
).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
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>');