[英]Sort javascript array by property or function value
我有一個包含原始值和計算值的數組。 我希望能夠基於原始值或計算值之一的結果對數組進行動態排序。 直到運行時,才知道所需的實際排序。
我整理了下面的示例( 此處為 plunker),以演示這種情況和可行的解決方案*。 我想知道如何改善這一點...具體來說,是:
Array.prototype.sortBy = function (property) {
return this.sort(mySort(property));
};
從該 stackoverflow響應中復制-EgeÖ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
類的本機對象被認為是最糟糕的做法。 那就是您提到的帖子。 問題是您不知道這將如何影響其他腳本的行為。
這是一個例子的例子,一旦操作數組原型,寫得不好就會引起問題。 我曾經在大型代碼的基礎上遇到過這種情況,但確實很難追蹤:
function BadUseOfForLoop(){
//You should NEVER use a for in loop to iterate over an array
//although some people do this and it works until you extend Array
var arr = [1,2,3,4];
for (key in arr){
console.log(arr[key]);
}
}
BadUseOfForLoop();
console.log("Extend Array...");
Array.prototype.sortBy = function(){
return "Doesnt matter...";
};
BadUseOfForLoop();
輸出:
1
2
3
4
Extend Array...
1
2
3
4
function (){
return "Doesnt matter...";
}
為避免警告,您可以做的一件事就是根本不擴展Array對象並創建一個幫助程序來幫助您。
var ArrayHelper = {
sortBy : function(arr, prop){
return function(){
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) {
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;
};
}
}
};
然后在您的代碼中...
ArrayHelper.sortBy(myItems,sortList[k]);
代替
myItems.sortBy(sortList[k]);
為了進一步閱讀該主題,《 Perfect Perfect Kills》一文討論了擴展原生對象是否是一個好主意,您會發現這不是一成不變的問題。 上面,我提出了一個問題,該問題在本博客文章中未討論,但實際上可能導致與其他代碼的沖突。
答案表明您不應擴展Array.prototype
東西。 就我個人而言,我不認為這是致命的罪行; 大多數庫都可以安全地處理這些情況。
也就是說,您可以包裝排序功能:
function ArraySorter(arr)
{
this.arr = arr;
}
ArraySorter.prototype.sortBy = function(prop) {
return this.arr.sort(mySort(prop));
}
var sortedItems = new ArraySorter(myItems).sortBy('whatever');
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.