簡體   English   中英

關於javascript的排序功能

[英]About a sort function for javascript

背景:

根據某些任務的需要,我需要一個簡單的排序功能。 為簡單起見,我編寫了另一個函數來將內置排序函數包裝為:

function sortBy(obj, extra, func){
    if(typeof func == 'function'){
        f = func;
    } else if(typeof extra != 'function'){
        eval('function f(a, b, ai, bi, e){return ' + func + '}');
    } else {
        var f = extra;
        extra = null;
    }

    var res = [];
    for(var i in obj){
        if(obj.hasOwnProperty(i)){
            obj[i]._k_ = i;
            res.push(obj[i]);
        }
    }

    res.sort(function(a, b){
        if(f(a, b, a._k_, b._k_, extra)){
            return 1;
        } else {
            return -1;
        }
    })

    return res;
}

我的嘗試是:

  1. 可以直接對對象進行排序
  2. 將原始對象保留為哈希表
  3. 允許一些簡單的語法

例如,

var data ={
    12: {age:27, name:'pop', role: 'Programmer'},
    32: {age:25, name:'james', role: 'Accontant'},
    123:{age:19, name:'jerry', role:'Sales Representative'},
    15:{age:22, name:'jerry', role:'Coder'},
    17:{age:19, name:'jerry', role:'Tester'},
    43:{age:14, name:'anna', role: 'Manager'},
    55: {age:31, name:'luke', role:'Analyst'}
};

有幾種用法:

var b = sortBy(data, '', 'a.age < b.age'); // a simple sort, order by age
var b = sortBy(data, 19, 'b.age == e');    // pick up all records of age 19, and put them in the beginning
var b = sortBy(data, function(a, b){return a.name > b.name});  // anonymous sort function is also allowed

雖然它在我們的代碼中按預期工作,但我想提出一些問題:

  1. 使用eval從字符串創建排序函數是否有任何關鍵問題?
  2. 是否有關於排序函數返回-1(nagative),0和1(正)的故事? 我們可以將代碼更改為“return if(f(a,b, a.kb.k ,extra)”,而不是返回1或-1?我們發現它在我們的firefox和chrome中有效,但不確定是否這樣做是安全的。

1.使用eval從字符串創建排序函數是否存在任何問題?

本身不是,但它確實遇到與使用字符串調用其他eval樣式函數相同的缺陷,例如setTimeout()Function()構造函數。 只要您信任字符串的來源,就沒有真正的問題。 但是,我會考慮使用Function構造Function

f = new Function(a, b, ai, bi, e, 'return ' + func);

它更易於管理,它肯定比評估函數聲明更合適。

2.是否有關於排序函數返回-1(nagative),0和1(正數)的故事?

沒有真正理解你的問題的這一部分,但是如果兩個項目在比較中是相同的,那么你的功能似乎並沒有解決該怎么做。 根據結果​​,您應該返回小於0,0或大於0的值。 最好的方法是使用String.prototype.localeCompare()

return String.prototype.localeCompare.call(a, b);

嘗試制作它,這樣你只需要在一小部分上做eval:

(小提琴: http//jsfiddle.net/maniator/SpJbN/

function sortBy(obj, extra, func){
    var f = null;
    if(typeof func == 'function'){
        f = func;
    } else if(typeof extra != 'function'){
        f = function(a, b, ai, bi, e){
            return eval(func); // <-- smaller part
        }
    } else {
        f = extra;
        extra = null;
    }

    var res = [];
    for(var i in obj){
        if(obj.hasOwnProperty(i)){
            obj[i]._k_ = i;
            res.push(obj[i]);
        }
    }

    res.sort(function(a, b){
        if(f(a, b, a._k_, b._k_, extra)){
            return 1;
        } else {
            return -1;
        }
    })

    return res;
}
  1. 感謝Andy,我們將代碼更改為

    var f = new Function('a,b,ai,bi,e','return'+ func);

請注意,參數應該作為字符串傳遞,請查看: https//developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function

  1. 關於第二個問題,我認為這是因為我們試圖更明確地進行排序功能。 例如,

    排序([1,2,3,5,1],'','a <b')==> [1,1,2,3,5]

對我們來說'a <b'的字面含義是“后一項比前項更大”,因此數組被排序為[1,1,2,3,5]。

另一個例子,'a.age <b.age'將按照年輕人在olders之前的順序返回記錄。

這就是我要求的原因我們可以使用真或假而不是-1,0,1。

我們繼續做一些小測試,找出一些東西,想與大家分享。

例如:

var b = [
    {age:27, name:'pop 2', role: 'Programmer'},
    {age:19, name:'james', role: 'Accontant'},
    {age:19, name:'jerry', role:'Sales Representative'},
    {age:22, name:'jerry', role:'Coder'},
    {age:19, name:'jerry', role:'Tester'},
    {age:14, name:'anna', role: 'Manager'},
    {age:19, name:'luke', role:'Analyst'},
    {age:27, name:'pop', role: 'Programmer'},
    {age:14, name:'anna 2', role: 'Manager'}
];

b.sort(function(a, b) {return a.age - b.age > 0? 1: -1}); // #1
b.sort(function(a, b) {return a.age > b.age});  // #2
b.sort(function(a, b) {return a.age - b.age});  // #3

雖然上面的排序返回相同的結果,但試試這個:

b.sort(function(a, b) {return a.age - b.age < 0? -1: 1});  // #4

在此聲明中,記錄仍按年齡排序,但訂單在同一年齡組內被撤銷。

#1和#2偶然與#3相同。 如果瀏覽器使用不同的算法來實現排序功能,則#1和#2的行為可能類似於#4。 如果你對結果的順序很嚴格,當'a'等於項'b'時,你需要顯式地返回0。

此外,正如Andy指出的那樣,在某些情況下(例如,#4),如果我們沒有明確地返回0,則可能會進行不必要的交換,這可能會影響性能。

我們之前沒有注意到這一點的原因是因為我們不關心組內的順序,只要記錄按特定屬性排序。

我認為傳遞一個進行比較的函數是合適的。 所以像

sort(somedata, function(a, b) {
    return a < b;
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM