2011-05-23 264 views
7

我一直在解決這個問題,整天沒有一個好的解決方案。 Google也沒什麼幫助。我有一個腳本,需要接受具有未知數量的行/列的二維數組。該腳本還需要接受包含要排序的列的列表的一維數組,以及包含要排序的順序的另一個數組。此次電話會議將看起來有點像這樣:如何在JavaScript中通過多列對多維數組進行排序?

var orderList = {0,4,3,1}; 
var orderDir = {asc,desc,desc,asc}; 
dataArr = do2DArraySort(dataArr, orderList, orderDir); 

功能do2DArraySort應當由第三返回dataArr陣列由第一列(升序)排序,然後由第五(按降序排列),然後(按降序排列),然後排在第二位(按降序排列)。使用下面的代碼,我能夠使它達到兩個深層次,但是一旦我嘗試添加第三個排序列,就會崩潰。我明白爲什麼,但我找不出一個好方法來實現它。

有沒有這樣做的標準方式?有人可以在網上給我一個好的劇本,我可以學習和用作模板嗎?或者可以有人建議修改我的代碼,使其工作?

謝謝!

//appends an array content to the original array 
function addToArray(originalArray, addArray) { 
    if (addArray.length != 0) { 
     var curLength = 0; 
     curLength = originalArray.length; 
     var maxLength = 0; 
     maxLength = curLength + addArray.length; 
     var itrerateArray = 0; 
     for (var r = curLength; r < maxLength; r++) { 
      originalArray[r] = addArray[itrerateArray]; 
      itrerateArray++; 
     } 
    } 
} 

function do2DArraySort(arrayToBeSorted, sortColumnArray, sortDirectionArray) { 
    if (arrayToBeSorted == "undefined" || arrayToBeSorted == "null") return arrayToBeSorted; 
    if (arrayToBeSorted.length == 0) return arrayToBeSorted; 
    if (sortColumnArray.length == 0) return arrayToBeSorted; 
    tempArray = arrayToBeSorted; 
    var totalLength = sortColumnArray.length; 
    for(var m = 0; m < totalLength; m++) { 
     if (m == 0) { 
      doBubbleSort(tempArray, tempArray.length, sortColumnArray[m], sortDirectionArray[m]);   
     } else {  
      doMultipleSort(tempArray, sortColumnArray[m], sortColumnArray[m-1], sortDirectionArray[m]); 
     } 
    } 
    return tempArray; 
} 

//check if a value exists in a single dimensional array 
function checkIfExists(arrayToSearch, valueToSearch) { 
    if (arrayToSearch == "undefined" || arrayToSearch == "null") return false; 
    if (arrayToSearch.length == 0) return false; 
    for (var k = 0; k < arrayToSearch.length; k++) { 
     if (arrayToSearch[k] == valueToSearch) return true; 
    } 
    return false; 
} 

//sorts an 2D array based on the distinct values of the previous column 
function doMultipleSort(sortedArray, currentCol, prevCol, sortDirection) { 
    var resultArray = new Array(); 
    var newdistinctValuesArray = new Array(); 
    //finding distinct previous column values 
    for (var n = 0; n < sortedArray.length; n++) { 
     if (checkIfExists(newdistinctValuesArray, sortedArray[n][prevCol]) == false) newdistinctValuesArray.push(sortedArray[n][prevCol]); 
    } 
    var recCursor = 0; 
    var newTempArray = new Array(); var toStoreArray = 0; 
    //for each of the distinct values 
    for (var x = 0; x < newdistinctValuesArray.length; x++) { 
     toStoreArray = 0; 
     newTempArray = new Array(); 
     //find the rows with the same previous column value 
     for (var y = 0; y < sortedArray.length; y++) { 
      if (sortedArray[y][prevCol] == newdistinctValuesArray[x]) { 
       newTempArray[toStoreArray] = sortedArray[y]; 
       toStoreArray++; 
      } 
     }  //sort the row based on the current column 
     doBubbleSort(newTempArray, newTempArray.length, currentCol, sortDirection); 
     //append it to the result array 
     addToArray(resultArray, newTempArray); 
    } 
    tempArray = resultArray; 
} 

回答

23

字面[]陣列優於new Array。符號{0,4,3,1}無效,應該是[0,4,3,1]

是否有必要重新發明輪子?兩個陣列可以使用加入了:

originalArray = originalArray.concat(addArray); 

元素可以被附加到使用端:

array.push(element); 

陣列具有用於排序的陣列的方法。默認情況下,它按照數字排序:

// sort elements numerically 
var array = [1, 3, 2]; 
array.sort(); // array becomes [1, 2, 3] 

數組也可以顛倒。繼續前面的例子:

array = array.reverse(); //yields [3, 2, 1] 

要提供自定義排序,你可以通過可選的功能參數array.sort():如果元素等於另一元素

array = []; 
array[0] = [1, "first element"]; 
array[1] = [3, "second element"]; 
array[2] = [2, "third element"]; 
array.sort(function (element_a, element_b) { 
    return element_a[0] - element_b[0]; 
}); 
/** array becomes (in order): 
* [1, "first element"] 
* [2, "third element"] 
* [3, "second element"] 
*/ 

元素將保留自己的位置。使用這個,你可以結合多個排序算法。您必須以相反的順序應用您的排序偏好,因爲最後一種排序優先於先前排序。爲了下面的陣列由第一列(降序)進行排序,然後第二列(升序):

array = []; 
array.push([1, 2, 4]); 
array.push([1, 3, 3]); 
array.push([2, 1, 3]); 
array.push([1, 2, 3]); 
// sort on second column 
array.sort(function (element_a, element_b) { 
    return element_a[1] - element_b[1]; 
}); 
// sort on first column, reverse sort 
array.sort(function (element_a, element_b) { 
    return element_b[0] - element_a[0]; 
}); 
/** result (note, 3rd column is not sorted, so the order of row 2+3 is preserved) 
* [2, 1, 3] 
* [1, 2, 4] (row 2) 
* [1, 2, 3] (row 3) 
* [1, 3, 3] 
*/ 

拉丁字符串(即英語,德語,荷蘭語)排序,使用String.localeCompare

array.sort(function (element_a, element_b) { 
    return element_a.localeCompare(element_b); 
}); 

排序日期的從Date對象,用自己的毫秒錶示:

array.sort(function (element_a, element_b) { 
    return element_a.getTime() - element_b.getTime(); 
}); 

您可以應用這種功能都挺只需遵循以下規則:

x是比較兩個值的結果,應通過傳遞給array.sort的函數返回兩個值。

  1. x < 0element_a應該來之前element_b
  2. x = 0element_aelement_b相等,的元素是不能交換
  3. x > 0element_a應該基於Lekensteyn出色的響應之後element_b
+0

謝謝;這太棒了,非常有啓發性。我現在要做一些進一步的研究。它看起來像這個偉大的假設所有元素都是數字,但由於我的數組可能包含數字,日期,字符等的混合,我需要弄清楚如何修改排序內的函數來確定字段類型並進行相應的排序。你碰巧知道一個很好的資源,你可以指點我嗎? – Nicholas 2011-05-23 19:30:21

+0

@Nicholas:我包含了一個例子,用於對日期對象和字符串進行排序。如果你理解數組的用法並且知道一些Javascript,你可以對所有提供排序算法的需求進行排序。如果不清楚,可以添加一條評論來解釋。 – Lekensteyn 2011-05-23 20:40:04

+0

Lekensteyn;再次謝謝你。我覺得我現在對自己的理解已經夠好了(很危險);)。我發現基本的排序算法似乎在日期中工作得很好,而不必使用getTime方法。我是否錯過了跳過這些的缺陷?你是一個真正的救星。 :) – Nicholas 2011-05-24 15:03:05

0

我建議寫一個高階函數,它接受了orderList和orderDir作爲參數,並返回一個可以直接傳遞到陣列#排序比較功能。通過這種方式,您可以嘗試不同的實現(例如,爲簡化性能而進行交易)。

這個未經測試的代碼演示了這個想法:

var getComparator = function(orderList, orderDir) { 
    var len = orderList.length; // XXX: assume == orderDir.length 
    return function(a, b) { 
    var cmp, ax, bx, i; 
    for (i=0; i<len; i++) { # For each field and direction... 
     ax = a[orderList[i]]; 
     bx = b[orderList[i]]; 
     cmp = ax.localeCompare(bx); # compare elements... 
     if (cmp != 0) { # if not equal then indicate order... 
     return (orderDir[i]=='asc') ? -1 : 1; 
     } 
    } 
    return 0; # otherwise, indicate equality. 
    }; 
}; 
dataArr.sort(getComparator(orderList, orderDir)); 

注意,你要小心使用「localeCompare」與減法字符串VS數字,或許這方面可以進行參數的getComparator功能以及。

0

來,我開發了以下解決方案以滿足我的需求。我還沒有對它進行完整的QA測試,也不知道它是否完美(實際上,我確信它不是),但我希望其他人可以從中獲得一些用途並在此基礎上進行構建他們的需求。如果需要進行重大更改,我會發布更新。

function do2DArraySort(dataArr, orderList, orderDir) { 
    for (x=orderList.length-1; x >= 0; x--) { 
     if (orderDir[x] == 'asc') { 
      dataArr.sort(sortMethodFunctionAsc); 
     } else { 
      dataArr.sort(sortMethodFunctionDesc); 
     } 
    } 

    return dataArr; 
} 

function sortMethodFunctionAsc(a, b) { 
    if ((IsNumeric(a[orderList[x]]) && IsNumeric(b[orderList[x]])) || (IsDate(a[orderList[x]]) && IsDate(b[orderList[x]]))) { 
     return a[orderList[x]] - b[orderList[x]]; 
    } else { 
     if (a[orderList[x]].toString() > b[orderList[x]].toString()) { 
      return 1; 
     } else if (a[orderList[x]].toString() < b[orderList[x]].toString()) { 
      return -1; 
     } else { 
      return 0; 
     } 
    } 
} 

function sortMethodFunctionDesc(a, b) { 
    if ((IsNumeric(a[orderList[x]]) && IsNumeric(b[orderList[x]])) || (IsDate(a[orderList[x]]) && IsDate(b[orderList[x]]))) { 
     return b[orderList[x]] - a[orderList[x]]; 
    } else { 
     if (a[orderList[x]].toString() < b[orderList[x]].toString()) { 
      return 1; 
     } else if (a[orderList[x]].toString() > b[orderList[x]].toString()) { 
      return -1; 
     } else { 
      return 0; 
     } 
    } 
} 


function IsNumeric(input) { 
    return (input - 0) == input && input.length > 0; 
} 

function IsDate(testValue) { 
    var returnValue = false; 
    var testDate; 
    try { 
     testDate = new Date(testValue); 
     if (!isNaN(testDate)) { 
      returnValue = true; 
     } else { 
      returnValue = false; 
     } 
    } 
    catch (e) { 
     returnValue = false; 
    } 
    return returnValue; 
} 
相關問題