Как рекурсивно искать дерево объектов и возвращать соответствующий объект на основе ключа/значения с использованием JavaScript/Prototype 1.7
У меня есть некоторые данные вложенных объектов, и я хочу их искать и возвращать соответствующий объект на основе идентификатора.
var data = [{id: 0, name: 'Template 0', subComponents:[
{id: 1, name: 'Template 1', subItems:[
{id: 2, name: 'Template 2', subComponents:[{id: 3, name: 'Template 3'}], subItems: [{id: 4, name: 'Template 4'}]}
]}
]}
];
Итак, я хочу сделать что-то вроде этого
getObjectByKeyValue({id: 3})
и вернуть его
{id: 3, name: 'Template 3'}
Это должно быть сделано в целом, потому что у меня есть subItems, и subComponents, у которых каждый может иметь детей.
Я попробовал это с помощью Prototype 1.7 и не повезло - я думаю, что это просто ищет массив, а не дерево с его суб-узлами:
data.find(function(s){return s.id == 4;})
Спасибо заранее!!!!!!
Ответы
Ответ 1
Я пошел немного другим путем и сделал метод findKey
Object type:
Object.prototype.findKey = function(keyObj) {
var p, key, val, tRet;
for (p in keyObj) {
if (keyObj.hasOwnProperty(p)) {
key = p;
val = keyObj[p];
}
}
for (p in this) {
if (p == key) {
if (this[p] == val) {
return this;
}
} else if (this[p] instanceof Object) {
if (this.hasOwnProperty(p)) {
tRet = this[p].findKey(keyObj);
if (tRet) { return tRet; }
}
}
}
return false;
};
Которое вы вызываете непосредственно на объект данных, передавая ключ/значение, которое вы ищете:
data.findKey({ id: 3 });
Обратите внимание, что эта функция позволяет вам найти объект на основе любого ключа:
data.findKey({ name: 'Template 0' });
See example → (open console to view result)
Ответ 2
Не лучшее и окончательное решение.
Но вы можете начать с того, что вы ищете...
var data = [{id: 0, name: 'Template 0', subComponents:[
{id: 1, name: 'Template 1', subItems:[
{id: 2, name: 'Template 2', subComponents:[{id: 3, name: 'Template 3'}], subItems: [{id: 4, name: 'Template 4'}]}
]}
]}
];
function returnObject(data,key,parent){
for(var v in data){
var d = data[v];
if(d==key){
return parent[0];
}
if(d instanceof Object){
return returnObject(d,key,data);
};
}
}
function returnObjectWrapper(datavar,key){
return returnObject(datavar,key.id)
}
returnObjectWrapper(data,{id:3})
Ответ 3
См. мое решение ниже или http://jsfiddle.net/8Y6zq/:
var findByKey = function (obj, key) {
var j, key = key || '', obj = obj || {}, keys = key.split("."),
sObj = [], ssObj = [], isSelector = !!(keys.length > 0);
var findKey = function (obj, key) {
var k;
for (k in obj) {
if (k === key) {
sObj.push(obj[k]);
} else if (typeof obj[k] == 'object') {
findKey(obj[k], key);
}
}
};
if (isSelector) {
var nKey = keys.shift();
findKey(obj, nKey);
while (keys.length > 0) {
nKey = keys.shift();
if (sObj.length > 0) {
ssObj = sObj.slice(0), sObj = [];
for (j in ssObj) {
findKey(ssObj[j], nKey);
}
}
}
} else {
findKey(obj, key);
}
// return occurrences of key in array
return (sObj.length === 1) ? sObj.pop() : sObj;
};
var data = [
{id: 0, name: 'Template 0', subComponents: [
{id: 1, name: 'Template 1', subItems: [
{id: 2, name: 'Template 2', subComponents: [
{id: 3, name: 'Template 3'}
], subItems: [
{id: 4, name: 'Template 4'}
]}
]}
]},
{subComponents:{
comp1:'comp1 value',
comp2:'comp2 value',
}}
];
alert(JSON.stringify(findByKey(data, 'subComponents')));
alert(JSON.stringify(findByKey(data, 'subComponents.comp1')));
alert(JSON.stringify(findByKey(data, 'subComponents.comp2')));
В этой реализации мы можем использовать поиск по KEY или SELECTOR (например, "<paren_key>.<child_key_1>.<child_key_2>. ... <child_key_N>"
)
Ответ 4
Если вам действительно нужен поиск через данные дерева, возвращайте все результаты (а не уникальный ключ), вот небольшая измененная версия ответа mVChr:
Object.prototype.findKey = function (keyObj) {
var p, key, val, tRet;
var arr = [];
for (p in keyObj) {
if (keyObj.hasOwnProperty(p)) {
key = p;
val = keyObj[p];
}
}
for (p in this) {
if (p == key) {
if (this[p] == val) {
arr.push(this);
}
} else if (this[p] instanceof Object) {
if (this.hasOwnProperty(p)) {
tRet = this[p].findKey(keyObj);
if (tRet) {
for (var i = 0; i < tRet.length; i++)
arr.push(tRet[i]);
}
}
}
}
if (arr.length > 0)
return arr;
else
return false;
};