Есть ли лучший способ поиска массива JavaScript, чем использование jQuery?
Мне часто приходится искать массив javascript, содержащий объекты. Я хочу искать объект в массиве, который имеет свойство. Например, поиск массива объектов Person, для которых id/ключ человека === "ABC123"
Это можно сделать довольно легко, используя jQuery, используя метод $.each, и это то, на чем я остановился. Вы можете увидеть пример здесь в 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 use the prototype for now
var i = people.inArray("PIR000", "code");
$('#output').text(people[i].name);
Есть много вопросов, подобных этому, но мне еще предстоит увидеть одно решение, отличное от итерации (как, например, здесь).
Итак, вопрос... есть ли лучший способ?
Ответы
Ответ 1
$, каждый из них будет о O (n), я бы подумал. Любой простой цикл "для", который ломается, когда он находит применимый элемент, будет не более O (n), но в среднем будет меньше, если последние элементы массива не будут постоянно считаться соответствующими элементами. Array.filter - это метод, который работает, но не является родным для некоторых браузеров. Существуют чистые javascript-реализации метода Array.filter, если вы так хотели его использовать. Для браузеров, которые размещают его изначально, он, вероятно, будет выполняться быстрее, поскольку их реализация, вероятно, скомпилирована и запущена в собственном коде. Но метод фильтра всегда будет давать O (n), поскольку он "фильтрует" элементы массива в новый массив.
Я лично придерживался подхода for (int я = 0;...). Меньше накладных расходов на изменение сферы, вызывая другие функции, и вы можете легко "разбить" на согласованный элемент.
Я также хотел добавить, что вы можете использовать локальное хранилище баз данных (которое использует SqlLite), предоставляемое HTML 5. Это, очевидно, не поддерживается широко, но будет намного быстрее, чем любой другой подход к использованию 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
Ответ 2
В общем случае вы не можете получить элементы из массива быстрее, чем 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, поэтому было бы неплохо отправить серверную часть обработки, чтобы вы могли использовать более подходящий инструмент, например, как реляционную базу данных.
Ответ 3
Это не отвечает на ваш вопрос "поиска" как таковой, но это может быть решение для вас. Вы можете создать специализированный класс 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 элементов).
Ответ 4
Если вы намереваетесь сделать это много, тогда вам может понадобиться создать индекс для определенных свойств, чтобы элементы могли быть возвращены намного быстрее. например следующий реализует объект хранения, который добавляет и получает объекты, которые добавлены к нему.
Он хранит индекс имен объектов (если они есть), так что получение их является эффективным.
Вы заметите только удар производительности для большого количества объектов (скажем, более 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
Ответ 5
Может быть, вы можете закодировать его с помощью for..in. Смотрите: http://www.w3schools.com/js/js_loop_for_in.asp. Работает в стиле similair как php foreach.
Ответ 6
Если мне приходится много раз искать массив, я повторяю его один раз, в который я добавляю каждый ключ как свойство объекта, а затем просматриваю ключ в этом объекте. Это сохраняет цель всех поисков в O (n) + c. Хранение эффективно, поскольку объект хранит ссылки на данные массива, или они являются примитивами. Просто и быстро.