【问题标题】:How do I recursively search an object tree and return the matching object based on a key/value using JavaScript/Prototype 1.7如何递归搜索对象树并使用 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;})

提前谢谢!!!!!!

【问题讨论】:

    标签: javascript recursion tree prototype javascript-objects


    【解决方案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的作者

          【讨论】:

            猜你喜欢
            • 2015-07-06
            • 2011-10-12
            • 1970-01-01
            • 2014-04-08
            • 1970-01-01
            • 2019-02-03
            • 2020-01-26
            • 2021-09-16
            相关资源
            最近更新 更多