Say I have an array of Person objects:
var people = [{name: "Joe Schmo", age: 36}, {name: "JANE DOE", age: 40}];
and I have a function which can sort an array of strings case insensitively:
function caseInsensitiveSort(arr) { ... }
Is there any straightforward way to combine my existing sort function with Array.prototype.map
to sort the people
array just using the name
key?
I.e. it would produce
var people = [{name: "JANE DOE", age: 40}, {name: "Joe Schmo", age: 36}];
Doing it by hand is not hard in this particular case,
people.sort(function (a, b) {
return a.name.localeCompare(b.name);
});
but I can't think of a way of doing it that would allow me to use the pre-existing sort function. In a case where the sort function is more customized, that would be useful.
Edit: I believe that the core problem here is that to do this well, you need to be able to figure out what the original indices were mapped to when you sort the proxy array. Getting those new indices using JS's native sort
function does not seem possible in the general case. But I'd be happy to be proven wrong.
Edit: The way I was trying to do this is too inefficient to be useful. See the answer below for the solution using a comparison function instead.
You could use your existing function to get a sorted names array, then sort the people
array by comparing the index in the sorted names array.
var names = caseInsensitiveSort(people.map(function(person) {
return person.name;
}));
people.sort(function (a, b) {
return names.indexOf(a.name) - names.indexOf(b.name);
});
But this is not efficient, you should try to abstract out the compare logic from the caseInsensitiveSort
function into a caseInsensitiveCompare
function.
Then your example would become:
people.sort(function (a, b) {
return caseInsensitiveCompare(a.name, b.name);
});
Depending on how your caseInsensitiveSort()
function works, you could make use of a .toString()
method to do this:
var toSort = people.map(function (person) {
return {
person: person,
toString: function () {
return person.name;
}
};
});
caseInsensitiveSort(toSort);
people = toSort.map(function (item) { return item.person; });
If that is not an option, a messier yet still efficient approach is to sort the names, map them to their indices, and then sort based on that:
var names = people.map(function (person) { return person.name; });
caseInsensitiveSort(names);
var nameMap = {};
names.forEach(function (name, i) {
nameMap[name] = i;
});
people.sort(function (a, b) {
return nameMap[a.name] - nameMap[b.name];
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With