У меня есть массив, содержащий исходные значения, а также вычисленные значения. Я хотел бы иметь возможность сортировать массив динамически на основе либо необработанного значения, либо результата одного из вычисленных значений. Фактические виды, которые потребуются, не будут известны до времени выполнения.Сортировка массива javascript по значению или значению функции
Я собрал образец ниже (plunker here), который демонстрирует ситуацию и рабочее решение *. Я хотел бы знать, как улучшить это ... В частности, использование:
Array.prototype.sortBy = function (property) {
return this.sort(mySort(property));
};
копируется из ответа this StackOverflow - и Эге Özcan конкретно говорится
//Please don't just copy-paste this code.
//See the explanation at the end. A lot could break.
Я хотел бы понять, как для реализации этого алгоритма сортировки на моем объекте, не нарушая предупреждение «Много может сломать» (что я не понимаю).
* Одна из вещей, которые мне нравятся в stackoverflow, заключается в том, что процесс формирования вопроса хорошо часто приводит к упрощению проблемы до того момента, когда появляется (не обязательно) решение. Я начал эту проблему, не имея возможности сортировать на основе свойства или вычисленного значения. Теперь я ищу подтверждение/совершенствование реализации.
Образец:
var rawData = [
{ "Id": 3, "itemCount": 3531, "val1": 905, "val2": 172 },
{ "Id": 2, "itemCount": 3111, "val1": 799, "val2": 147 },
{ "Id": 4, "itemCount": 3411, "val1": 871, "val2": 199 },
{ "Id": 5, "itemCount": 3414, "val1": 892, "val2": 178 },
{ "Id": 1, "itemCount": 3182, "val1": 845, "val2": 155 }
];
function MyItem(item) {
var self = this;
for (var val in item) {
if (item.hasOwnProperty(val)) {
self[val] = item[val];
}
}
}
function extendMyItems() {
MyItem.prototype.computedOne = function() {
var input = this;
return input.itemCount/input.val1;
};
MyItem.prototype.computedTwo = function() {
var input = this;
return input.val1 * input.val2;
};
}
function getItems(input) {
var ret = [];
for (var i = 0; i < input.length; i++) {
var item = new MyItem(input[i]);
ret.push(item);
}
return ret;
}
function doIt() {
Array.prototype.sortBy = function (property) {
return this.sort(mySort(property));
};
extendMyItems();
var sortList = [{ "sortKey": "Id", "sortOrder": "asc" },
{ "sortKey": "val1", "sortOrder": "asc" },
{ "sortKey": "val2", "sortOrder": "desc" },
{ "sortKey": "computedOne", "sortOrder": "desc", "isComputed": true },
{ "sortKey": "Id", "sortOrder": "desc" },
{ "sortKey": "computedTwo", "sortOrder": "asc", "isComputed": true }];
// get the array of MyItem
var myItems = getItems(rawData);
for (var k = 0; k < sortList.length; k++) {
myItems.sortBy(sortList[k]);
// process the sorted items here (ranking/scoring, etc)
for (var p = 0; p < myItems.length; p++) {
console.log('Id: ' + myItems[p].Id + ' val1: ' + myItems[p].val1 + ' val2: ' + myItems[p].val2 + ' c1: ' + myItems[p].computedOne() + ' c2: ' + myItems[p].computedTwo());
}
}
function mySort(srt) {
var so = srt.sortOrder == 'asc' ? 1 : -1;
var key = srt.sortKey;
var result = 0;
console.log(srt.sortKey + ' ' + srt.sortOrder + ':');
return function (a, b) {
if (srt.isComputed) {
// this seems like a hack - is there a better way to switch between property and function value????
result = (a[key]() < b[key]()) ? -1 : (a[key]() > b[key]()) ? 1 : 0;
} else {
result = (a[key] < b[key]) ? -1 : (a[key] > b[key]) ? 1 : 0;
}
return result * so;
};
}
}
Реализация выглядит хорошо; в чем именно проблема? –
Привет, Джек, просто интересно, если 'Array.prototype.sortBy' является правильным способом для этого ... Я новичок в javascript, поэтому я не понял, что« Множество может сломать »предупреждение из того, что я скопировал/вставить. – Kevin
См. [Почему используется «для ... в» с итерацией массива такая плохая идея?] (Http://stackoverflow.com/questions/500504/why-is-using-for-in-with-array-iteration-such -а-плохая идея /) о том, что может сломаться. И ответ, который вы связали, уже объясняет, как обойти это. – Bergi