如何递归搜索对象树并使用 JavaScript/Prototype 1.7 基于键/值返回匹配的对象

Posted

技术标签:

【中文标题】如何递归搜索对象树并使用 JavaScript/Prototype 1.7 基于键/值返回匹配的对象【英文标题】:How do I recursively search an object tree and return the matching object based on a key/value using JavaScript/Prototype 1.7 【发布时间】:2011-03-26 15:52:46 【问题描述】:

我有一些嵌套的对象数据,我想搜索它并根据 id 返回匹配的对象。

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'

一般来说,这是必须完成的,因为我有子项和子组件,每个子项都可以有子项。

我使用 Prototype 1.7 进行了尝试,但没有运气 - 我认为这只是搜索一个数组,而不是一个带有子节点的树:

data.find(function(s)return s.id == 4;)

提前谢谢!!!!!!

【问题讨论】:

【参考方案1】:

我走了一条稍微不同的路线,将 findKey 方法设为 Object 原型:

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 →(打开控制台查看结果)

【讨论】:

我更喜欢这个解决方案,但是当原型库混合在一起时这似乎不起作用 - 任何线索如何使它与原型库一起工作? 我将 fiddle 切换为包含 Prototype 1.7 库,它仍然适用于我,所以我不确定您遇到了什么问题。 不错的解决方案。如果我想基于多个键进行搜索怎么办。为相同添加了question here 糟糕糟糕糟糕!原生对象原型的扩展! 如果你不想扩展对象原型,这很容易修改为一个独立的方法——只需传入数据以搜索并用传递的参数名称替换对它的引用。跨度> 【参考方案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;
;

【讨论】:

【参考方案5】:

我们现在使用object-scan 来完成这样的数据处理任务。一旦您了解如何使用它,它就会非常强大。以下是您回答问题的方式

// const objectScan = require('object-scan');

const find = (id, input) => objectScan(['**'], 
  abort: true,
  rtn: 'value',
  filterFn: ( value ) => value.id === id
)(input);

const 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' ] ] ] ];

console.log(find(3, data));
// =>  id: 3, name: 'Template 3' 
.as-console-wrapper max-height: 100% !important; top: 0
&lt;script src="https://bundle.run/object-scan@13.8.0"&gt;&lt;/script&gt;

免责声明:我是object-scan的作者

【讨论】:

以上是关于如何递归搜索对象树并使用 JavaScript/Prototype 1.7 基于键/值返回匹配的对象的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript中嵌套对象结构中的递归树搜索

7-8 中序遍历树并判断是否为二叉搜索树 (20 分)

如何在 Apache Spark 中实现递归算法?

sh shell函数用于爬网dns树并在每个父区域中搜索SRV记录。一旦找到第一个SRV记录,它将退出。

python 打印Linux设备树并可选择搜索该树中的字符串。需要顶级dts文件作为输入。 #linux #python

2021-06-12:已知一棵搜索二叉树上没有重复值的节点,现在有一个数组arr,是这棵搜索二叉树先序遍历的结果。请根据arr生成整棵树并返回头节点。