簡體   English   中英

有沒有比使用jQuery更好的搜索JavaScript數組的方法?

[英]Is there a Better Way to Search a JavaScript Array than Using jQuery's each?

我經常需要搜索包含對象的javascript數組。 我想在數組中搜索具有屬性匹配的對象。 例如,在Person對象的數組中搜索person的id / key ===“ABC123”

使用$ .each方法使用jQuery可以很容易地完成它,這是我所確定的。 你可以在jsFiddle中看到這里的例子。 http://jsfiddle.net/johnpapa/EJAFG/

我想知道是否有其他人找到了更快和/或更好的方法來做到這一點?

var Person = function(code, name) {
    this.code = code;
    this.name = name;
};
var people = [
    new Person("ABC123", "Tooth Fairy"),
    new Person("DEF456", "Santa Claus"),
    new Person("PIR000", "Jack Sparrow"),
    new Person("XYZ987", "Easter Bunny")
    ];

var utils = {};
// Could create a utility function to do this
utils.inArray = function(searchFor, property) {
    var retVal = -1;
    $.each(this, function(index, item) {
        if (item.hasOwnProperty(property)) {
            if (item[property].toLowerCase() === searchFor.toLowerCase()) {
                retVal = index;
                return false;
            }
        }
    });
    return retVal;
};

// or we could create a function on the Array prototype indirectly
Array.prototype.inArray = utils.inArray;

// let's use the prototype for now
var i = people.inArray("PIR000", "code");
$('#output').text(people[i].name);

有很多問題與此類似,但我還沒有看到一個解決方案,而不是迭代(就像我在這里做的那樣)。

所以問題是......有更好的方法嗎?

$ .each將是關於O(n)我會想。 任何簡單的“for”循環在找到適用的項目時會斷開,最多只能是O(n),但平均來說會更少,除非數組的后一項經常被發現是匹配元素。 Array.filter是一種有效的方法,但不是某些瀏覽器的原生方法。 如果你希望使用它,那么Array.filter方法有純粹的javascript實現。 對於本機托管它的瀏覽器,它可能執行得更快,因為它們的實現可能是在本機代碼中編譯和運行的。 但是過濾器方法總是會產生O(n),因為它將數組的元素“過濾”成一個新數組。

我個人堅持使用for(int i = 0; ...)方法。 通過調用其他函數可以減少范圍更改的開銷,並且可以輕松地“中斷”匹配的元素。

我還想補充一點,你可以使用HTML 5提供的本地數據庫存儲(使用SqlLite)。這顯然不受廣泛支持,但是在給定足夠大的數據集的情況下,它會比任何其他javascript方法快得多。 如果你想查看它,這是一個鏈接:

http://blog.darkcrimson.com/2010/05/local-databases/

以下是一種有點不太常見的做法:理論上,您可以將數據編入索引並以快速方式使用這些指標進行檢索。 您不是將數據存儲在javascript數組中,而是將其存儲在DOM中,並使用CSS類(如“data-id-5”)對元素進行“索引”。 這為您提供了使用大多數主流瀏覽器內置的本機選擇器API的優勢。 這是一個例子:

DOM:

 <div id="datastuff" style="display:none">
     <span class="data-id-ABC123" data-person='{"code": "ABC123", "name": "Tooth Fairy"}'></span>
     <span class="data-id-DEF456" data-person='{"code": "DEF456", "name": "Santa Claus"}'></span>
     <span class="data-id-PIR000" data-person='{"code": "PIR000", "name": "Jack Sparrow"}'></span>
     <span class="data-id-XYZ987" data-person='{"code": "XYZ987", "name": "Easter Bunny"}'></span>
 </div>

現在我們可以使用jQuery並查詢它:我們將查詢“ABC123”的鍵:

var person = $(".data-id-ABC123").data("person");
console.log(person.name);//Tooth Fairy

通常,除非您知道要索引的內容,否則無法比O(n)更快地從數組中獲取元素。

例如,如果要索引可比較的somethnig,則可以對數組進行排序並執行二進制搜索。

如果您正在對列進行搜索並且值為int或字符串,則可以使用普通Javascript對象作為哈希表。

var people = [
    new Person("ABC123", "Tooth Fairy"),
    new Person("DEF456", "Santa Claus"),
    new Person("PIR000", "Jack Sparrow"),
    new Person("XYZ987", "Easter Bunny")
];

var people_table = {};
for(var i=0; i<people.length; i++){
    people_table[ people[i].id ] = people[i];
}

//fast search:
var someone = people_table['ABC123'];

在某一點之后,查詢變得太復雜,無法在Javascript中輕松完成,因此發送處理服務器端可能是個好主意,因此您可以使用更合適的工具,例如關系數據庫。

這本身並不能解答您的“搜索”問題,但它可能是您的解決方案。 您可以創建一個專門的PersonArray類,為其中的人PersonArray索引。 這種方法的性能是O(1),但它使用更多的內存。

var PersonArray = function(persons) {
    this.elements = {};
    var i;
    for (i=0; i < persons.length; i++) {
        this.elements[persons[i].code] = persons[i];
    }
};

PersonArray.prototype.fromCode = function(s) {
    return this.elements[s];   
};

var people = new PersonArray([
    new Person("ABC123", "Tooth Fairy"),
    new Person("DEF456", "Santa Claus"),
    new Person("PIR000", "Jack Sparrow"),
    new Person("XYZ987", "Easter Bunny")
    ]);

console.log(people.fromCode("ABC123"));  // Prints a person
console.log(people.fromCode("DEF456"));  // Prints a person
console.log(people.fromCode("NONE"));  // Undefined

您也可以擴展此方法以索引其他字段。

另請參閱: 演示基准 (100,000個元素)。

如果您打算這么做,那么您可能希望為特定屬性創建索引,以便可以更快地返回項目。 例如,以下實現了一個存儲對象,用於添加和獲取添加到其中的對象。

它保留了對象名稱的索引(如果它們有一個),以便獲得它們是有效的。

您只會注意到大量對象的性能提升(例如超過100個)並且僅針對具有索引的那些(盡管您可以為任意數量的屬性創建索引,並且可以使用更通用的方法去做)。

function Storage() {
  this.store = [];
  this.nameIndex = {};
}

// Add item to the store, if has name property, add name to name index
Storage.prototype.addItem = function(item) {
  var idx = this.nameIndex;

  // If the item has a name property
  if (item.hasOwnProperty('name')) {

    // If already have an item with that name, add index of
    // this item to indexs of same named items
    if (idx.hasOwnProperty(item.name)) {
      idx[item.name].push(this.store.length);

    // Otherwise, add this item to the index
    } else {
      idx[item.name] = [this.store.length];


    }
  }  
  // Add the item to the store
  this.store.push(item);
}

// Returns a possibly empty array of items with matching names
Storage.prototype.getItemsByName = function(name) {
  var result = [];
  var names;

  if (this.nameIndex.hasOwnProperty(name)) {
    list = this.nameIndex[name];

      for (var i=0, iLen=list.length; i<iLen; i++) {
        result.push(this.store[list[i]]);
      }
  }
  return result;
}

// Generic method for any property and value
Storage.prototype.getItemsByAttributeValue = function(propName, propValue) {
  // loop through items, return array of 
  // those with matching property and value
}


var store = new Storage();

store.addItem({name:'fred',age:'9'});

var obj = store.getItemsByName('fred');

alert(obj[0].age); // 9

store.addItem({name:'sally',age:'12'});

obj = store.getItemsByName('sally');

alert(obj[0].age); //12

如果我必須重復搜索數組,那么我迭代一次,在其中我將每個鍵添加為對象的屬性,然后在該對象中查找鍵。 這使所有查找的目標保持在O(n)+ c。 存儲是有效的,因為對象存儲對數組數據的引用,或者它們是基元。 簡單快捷。

也許你可以用for..in循環它。 請參閱: http//www.w3schools.com/js/js_loop_for_in.asp 像php的foreach一樣以類似的方式工作。

暫無
暫無

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

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