JSON найти в JavaScript
есть ли лучший способ, кроме цикла, чтобы найти данные в JSON? Это для редактирования и удаления.
for(var k in objJsonResp) {
if (objJsonResp[k].txtId == id) {
if (action == 'delete') {
objJsonResp.splice(k,1);
} else {
objJsonResp[k] = newVal;
}
break;
}
}
данные расположены в виде списка карт.
Например:
[
{id:value, pId:value, cId:value,...},
{id:value, pId:value, cId:value,...},
...
]
5 ответов:
(вы не ищете через "JSON", вы ищете через массив-строка JSON уже была десериализована в граф объектов, в данном случае массив.)
варианты:
использовать объект вместо массива
если вы контролируете генерацию этой вещи, делает это есть быть массивом? Потому что если нет, то есть гораздо более простой способ.
скажите, что это ваш оригинал данные:
[ {"id": "one", "pId": "foo1", "cId": "bar1"}, {"id": "two", "pId": "foo2", "cId": "bar2"}, {"id": "three", "pId": "foo3", "cId": "bar3"} ]не могли бы вы сделать следующее вместо этого?
{ "one": {"pId": "foo1", "cId": "bar1"}, "two": {"pId": "foo2", "cId": "bar2"}, "three": {"pId": "foo3", "cId": "bar3"} }тогда найти соответствующую запись по ID тривиально:
id = "one"; // Or whatever var entry = objJsonResp[id];...как это обновление:
objJsonResp[id] = /* New value */;...и удалив его:
delete objJsonResp[id];это использует тот факт, что в JavaScript вы можете индексировать объект, используя имя свойства в качестве строки-и эта строка может быть литералом, или она может исходить из переменной, как с
idвыше.ввод ID-to-Index Map
(глупая идея, была выше. Хранится по историческим причинам.)
похоже, вам нужно, чтобы это был массив, и в этом случае нет лучшего способа, чем поиск по массиву, если вы не хотите поместить на него карту, что вы могли бы сделать, если у вас есть контроль над генерацией объекта. Например, скажем, у вас есть Это изначально:
[ {"id": "one", "pId": "foo1", "cId": "bar1"}, {"id": "two", "pId": "foo2", "cId": "bar2"}, {"id": "three", "pId": "foo3", "cId": "bar3"} ]генерирующий код может обеспечить ИД-индекс карты:
{ "index": { "one": 0, "two": 1, "three": 2 }, "data": [ {"id": "one", "pId": "foo1", "cId": "bar1"}, {"id": "two", "pId": "foo2", "cId": "bar2"}, {"id": "three", "pId": "foo3", "cId": "bar3"} ] }затем получение записи для идентификатора в переменной
idтривиально:var index = objJsonResp.index[id]; var obj = objJsonResp.data[index];это использует тот факт, что вы можете индексировать объекты с помощью имен свойств.
конечно, если вы это сделаете, вам придется обновить карту при изменении массива, что может стать проблемой обслуживания.
но если вы не контролируете генерацию объекта, или обновление карты идентификаторов к индексам тоже большая проблема с кодом и / или обслуживанием ora, тогда вам придется выполнить поиск грубой силы.
Поиск грубой силы (исправлено)
несколько OT (хотя вы сделал спросите, есть ли лучший способ :-) ), но ваш код для циклического перебора массива неверен. подробности здесь, но вы не можете использовать
for..inдля циклического перебора индексов массива (или, скорее, если вы это сделаете, вам придется приложить особые усилия для этого);for..inпетли через свойства объект, а не индексы массива. Ваш лучший выбор с не разреженным массивом (и ваш не разреженный) - это стандартный старомодный цикл:var k; for (k = 0; k < someArray.length; ++k) { /* ... */ }или
var k; for (k = someArray.length - 1; k >= 0; --k) { /* ... */ }в зависимости от того, что вы предпочитаете (последнее не всегда быстрее во всех реализациях, что противоречит моей интуиции, но мы есть). (С помощью редкие массив, вы можете использовать
for..inно опять же принимая особые меры, чтобы избежать ловушек; подробнее в статье связаны выше.)используя
for..inв массиве кажется работать в простых случаях, потому что массивы имеют свойства каждого из их индексов, и их только другие свойства по умолчанию (lengthи их методы) помечены как не перечислимые. Но он ломается, как только вы устанавливаете (или фреймворк устанавливает) любые другие свойства объекта массива (что совершенно верно; массивы-это просто объекты с немного специальной обработкой вокругlengthсвойства).
я столкнулся с этой проблемой для сложной модели с несколькими вложенными объектами. Хорошим примером того, что я смотрел, было бы следующее: допустим, у вас есть полароидный снимок. И эта картина затем помещается в багажник автомобиля. Автомобиль находится внутри большого ящика. Ящик находится в трюме большого корабля со многими другими ящиками. Я должен был обыскать трюм, заглянуть в ящики, проверить багажник, а затем искать существующую мою фотографию.
Я не мог найти любой хороший решения Онлайн для использования, и с помощью
.filter()работает только с массивами. Большинство решений предлагается просто проверить, еслиmodel["yourpicture"]существовало. Это было очень нежелательно, потому что, из примера, это будет только обыскивать трюм корабля, и мне нужен был способ получить их из более глубокого кроличьего отверстия.это рекурсивное решение, которое я сделал. В комментариях я подтвердил от T. J. Crowder, что рекурсивная версия будет необходима. Я думал, что поделюсь им, если кто-нибудь наткнется на аналогичная сложная ситуация.
function ContainsKeyValue( obj, key, value ){ if( obj[key] === value ) return true; for( all in obj ) { if( obj[all] != null && obj[all][key] === value ){ return true; } if( typeof obj[all] == "object" && obj[all]!= null ){ var found = ContainsKeyValue( obj[all], key, value ); if( found == true ) return true; } } return false; }это будет начинаться с заданного объекта внутри графика и рекурсивно вниз любые найденные объекты. Я использую его так:
var liveData = []; for( var items in viewmodel.Crates ) { if( ContainsKeyValue( viewmodel.Crates[items], "PictureId", 6 ) === true ) { liveData.push( viewmodel.Crates[items] ); } }который будет производить массив ящиков, которые содержали мою фотографию.
Zapping-вы можете использовать этот javascript lib; DefiantJS. Нет необходимости реструктурировать данные JSON в объекты, чтобы облегчить поиск. Вместо этого вы можете искать структуру JSON с выражением XPath следующим образом:
var data = [ { "id": "one", "pId": "foo1", "cId": "bar1" }, { "id": "two", "pId": "foo2", "cId": "bar2" }, { "id": "three", "pId": "foo3", "cId": "bar3" } ], res = JSON.search( data, '//*[id="one"]' ); console.log( res[0].cId ); // 'bar1'DefiantJS расширяет глобальный объект JSON с помощью нового метода; "поиск", который возвращает массив с совпадениями (пустой массив, если ни один не был найден). Вы можете попробовать это самостоятельно, вставив данные JSON и протестировав различные запросы XPath здесь:
http://www.defiantjs.com/#xpath_evaluator
XPath-это, как вы знаете, стандартизированный язык запросов.
Если данные JSON в вашем массиве отсортированы каким-либо образом, существует множество поисков, которые вы можете реализовать. Однако, если вы не имеете дело с большим количеством данных, то вы, вероятно, будете в порядке с операцией O(n) здесь (как и у вас). Все остальное, вероятно, было бы излишним.
Если вы делаете это более чем в одном месте в своем приложении, имеет смысл использовать клиентскую базу данных JSON, потому что создание пользовательских функций поиска является беспорядочным и менее доступным, чем альтернатива.
Проверьте ForerunnerDB, который предоставляет вам очень мощную систему базы данных JSON на стороне клиента и включает в себя очень простой язык запросов, чтобы помочь вам сделать именно то, что вы ищете:
// Create a new instance of ForerunnerDB and then ask for a database var fdb = new ForerunnerDB(), db = fdb.db('myTestDatabase'), coll; // Create our new collection (like a MySQL table) and change the default // primary key from "_id" to "id" coll = db.collection('myCollection', {primaryKey: 'id'}); // Insert our records into the collection coll.insert([ {"name":"my Name","id":12,"type":"car owner"}, {"name":"my Name2","id":13,"type":"car owner2"}, {"name":"my Name4","id":14,"type":"car owner3"}, {"name":"my Name4","id":15,"type":"car owner5"} ]); // Search the collection for the string "my nam" as a case insensitive // regular expression - this search will match all records because every // name field has the text "my Nam" in it var searchResultArray = coll.find({ name: /my nam/i }); console.log(searchResultArray); /* Outputs [ {"name":"my Name","id":12,"type":"car owner"}, {"name":"my Name2","id":13,"type":"car owner2"}, {"name":"my Name4","id":14,"type":"car owner3"}, {"name":"my Name4","id":15,"type":"car owner5"} ] */отказ от ответственности: я разработчик Предтеча.
Comments