【问题标题】:Get all keys of a deep object in Javascript在Javascript中获取深层对象的所有键
【发布时间】:2021-01-31 16:59:30
【问题描述】:

我有以下对象:

var abc = {
    1: "Raggruppamento a 1",
    2: "Raggruppamento a 2",
    3: "Raggruppamento a 3",
    4: "Raggruppamento a 4",
    count: '3',
    counter: {
        count: '3',
    },
    5: {
        test: "Raggruppamento a 1",

        tester: {
            name: "Georgi"
        }
    }
};

我想检索以下结果:

  • abc[1]
  • abc[2]
  • abc[3]
  • abc[4]
  • abc.count
  • abc.counter.count
  • abc[5]
  • abc[5].test
  • abc[5].tester
  • abc[5].tester.name

是否可以在插件的帮助下使用 nodejs?

【问题讨论】:

  • 仅供参考,这不是“数组”。
  • 对不起,只是没想到...

标签: javascript node.js


【解决方案1】:

你可以通过递归遍历对象来做到这一点:

function getDeepKeys(obj) {
    var keys = [];
    for(var key in obj) {
        keys.push(key);
        if(typeof obj[key] === "object") {
            var subkeys = getDeepKeys(obj[key]);
            keys = keys.concat(subkeys.map(function(subkey) {
                return key + "." + subkey;
            }));
        }
    }
    return keys;
}

在您问题中的对象上运行 getDeepKeys(abc) 将返回以下数组:

["1", "2", "3", "4", "5", "5.test", "5.tester", "5.tester.name", "count", "counter", "counter.count"]

【讨论】:

  • 刚刚在您的示例中发现了一个问题。如果他们的键是一个数字会发生什么?示例:abc.test[0] - 您的示例将输出错误的 abc.test.0。
  • @GeorgiK。 JavaScript 不区分字符串键和数字键。 test[0]test["0"] 是一回事。我不确定您使用此代码的目的是什么,为什么需要进行这种区分?
【解决方案2】:

较小的版本,没有副作用,函数体中只有 1 行:

function objectDeepKeys(obj){
  return Object.keys(obj).filter(key => obj[key] instanceof Object).map(key => objectDeepKeys(obj[key]).map(k => `${key}.${k}`)).reduce((x, y) => x.concat(y), Object.keys(obj))
}

var abc = {
    1: "Raggruppamento a 1",
    2: "Raggruppamento a 2",
    3: "Raggruppamento a 3",
    4: "Raggruppamento a 4",
    count: '3',
    counter: {
        count: '3',
    },
    5: {
        test: "Raggruppamento a 1",

        tester: {
            name: "Ross"
        }
    }
};

function objectDeepKeys(obj){
  return Object.keys(obj)
    .filter(key => obj[key] instanceof Object)
    .map(key => objectDeepKeys(obj[key]).map(k => `${key}.${k}`))
    .reduce((x, y) => x.concat(y), Object.keys(obj))
}

console.log(objectDeepKeys(abc))

【讨论】:

    【解决方案3】:

    我知道这篇文章有点老了……

    此代码涵盖了 JSON 对象格式的所有条件,例如对象、对象数组、嵌套数组对象、带有数组对象的嵌套对象等。

    getDeepKeys = function (obj) {
      var keys = [];
        for(var key in obj) {
            if(typeof obj[key] === "object" && !Array.isArray(obj[key])) {
                var subkeys = getDeepKeys(obj[key]);
                keys = keys.concat(subkeys.map(function(subkey) {
                    return key + "." + subkey;
                }));
            } else if(Array.isArray(obj[key])) {
                for(var i=0;i<obj[key].length;i++){
                   var subkeys = getDeepKeys(obj[key][i]);
                   keys = keys.concat(subkeys.map(function(subkey) {
                    return key + "[" + i + "]" + "." + subkey;
                   }));
                }
            } else {
              keys.push(key);
            }
        }
        return keys;
    }
    

    【讨论】:

    • 谢谢!这正是我一直在寻找的。我喜欢这个,因为与接受的答案不同,它返回最深的键而不是所有键: [ '1', '2', '3', '4', '5.test', '5.tester.name' , 'count', 'counter.count', ]
    【解决方案4】:

    考虑使用函数样式实现deepKeys。我们可以避免突变、变量重新分配、中间分配和其他副作用带来的麻烦 -

    1. 如果输入t 是一个对象,对于对象中的每个(k,v) 对,将k 附加到path 并在子问题v 上重复
    2. (归纳)输入不是一个对象。返回格式化的path

    我们可以这样编码 -

    const deepKeys = (t, path = []) =>
      Object(t) === t
        ? Object                                             // 1
            .entries(t)
            .flatMap(([k,v]) => deepKeys(v, [...path, k]))
        : [ path.join(".") ]                                 // 2
    
    const input =
      {1:"Raggruppamento a 1",2:"Raggruppamento a 2",3:"Raggruppamento a 3",4:"Raggruppamento a 4",count:'3',counter:{count:'3',},5:{test:"Raggruppamento a 1",tester:{name:"Georgi"}}}
    
    for (const path of deepKeys(input))
      console.log(path)

    实现这个程序的另一个很好的选择是 JavaScript 的生成器。注意这个deepKeys 和上面的实现之间的相似之处。他们都有效地做同样的事情 -

    function* deepKeys (t, path = [])
    { switch(t?.constructor)
      { case Object:
          for (const [k,v] of Object.entries(t))  // 1
            yield* deepKeys(v, [...path, k])
          break
        default:
          yield path.join(".")                    // 2
      }
    }
    
    const input =
      {1:"Raggruppamento a 1",2:"Raggruppamento a 2",3:"Raggruppamento a 3",4:"Raggruppamento a 4",count:'3',counter:{count:'3',},5:{test:"Raggruppamento a 1",tester:{name:"Georgi"}}}
    
    for (const path of deepKeys(input))
      console.log(path)

    deepKeys 的每个变体的输出都相同 -

    1
    2
    3
    4
    5.test
    5.tester.name
    count
    counter.count
    

    【讨论】:

      【解决方案5】:

      我使用此代码(对来自“Peter Olson”的先前代码进行了一些修复,使用了lodash)来获取密钥,并检查某些值是否为Date

      getDeepKeys = function (obj) {
        let keys = [];
        for (let key in Object.keys(obj)) {
          let value = obj[key];
          if (_.isDate(value)) {
            keys.push(key);
          } else if (_.isObject(value)) {
            let subkeys = getDeepKeys(value);
            keys = keys.concat(subkeys.map(function(subkey) {
              return key + "." + subkey;
            }));
          } else {
            keys.push(key)
          }
        }
        return keys;
      }
      

      我还检查了值是否为 mongoDBRef 使用的条件如下:((_.isObject(value)) &amp;&amp; (value &amp;&amp; value.oid))

      【讨论】:

        【解决方案6】:
          getDeepKeys = function (obj) {
        var keys = [];
          for(var key in obj) {
              if(typeof obj[key] === "object" && !Array.isArray(obj[key])) {
                  var subkeys = getDeepKeys(obj[key]);
                  keys = keys.concat(subkeys.map(function(subkey) {
                      return key + "." + subkey;
                  }));
              } else if(Array.isArray(obj[key])) {
                  for(var i=0;i<obj[key].length;i++){
                      if ( typeof (obj[key][i]) == "string") {
                         console.log(obj[key][i])
                         keys.push(key)
                      }
                      else{
                           var subkeys = getDeepKeys(obj[key][i]);
                     keys = keys.concat(subkeys.map(function(subkey) {
                      return key + "[" + i + "]" + "." + subkey;
                     }));
                      }
        
                  }
              } else {
                keys.push(key);
              }
          }
          return keys;
        

        }

        【讨论】:

          【解决方案7】:

          使用递归函数会有帮助

          findKeys = (obj, p) => {
          
          var parent = p
          for (let i of Object.keys(obj)) {
          
            if (typeof (obj[i]) === "object") {
              var k = p + "." + i
              console.log(k)
              this.findKeys(obj[i], k)
            } else {
              console.log(parent + "." + i)
            }
          }
          
           findKeys(abc,"abc")`
          

          【讨论】:

            猜你喜欢
            • 2011-05-22
            • 2019-12-06
            • 2019-07-18
            • 1970-01-01
            • 1970-01-01
            • 2014-12-24
            • 2018-12-10
            • 2021-10-22
            • 1970-01-01
            相关资源
            最近更新 更多