【问题标题】:How to get all keys with values from nested objects如何从嵌套对象中获取具有值的所有键
【发布时间】:2018-04-14 05:55:10
【问题描述】:

我正在寻找类似于Object.keys 的东西,但它适用于潜在的嵌套对象。它也不应该包括具有对象/数组值的键(它应该只包括具有直接字符串/数字/布尔值的键)。

示例 A

输入

{
   "check_id":12345,
   "check_name":"Name of HTTP check",
   "check_type":"HTTP"
}

预期输出

[
  "check_id",
  "check_name",
  "check_type"
]

Object.keys 适用于这样的扁平案例,但不适用于嵌套案例:

示例 B

输入

{
   "check_id":12345,
   "check_name":"Name of HTTP check",
   "check_type":"HTTP",
   "tags":[
     "example_tag"
   ],
   "check_params":{
      "basic_auth":false,
      "params":[
        "size"
      ],
      "encryption": {
        "enabled": true,
      }
   }
}

预期输出

[
  "check_id",
  "check_name",
  "check_type",
  "check_params.basic_auth",
  "check_params.encryption.enabled"
]

请注意,这不包括 tagscheck_paramscheck_params.paramscheck_params.encryption,因为这些值是数组/对象。

问题

有没有这样的图书馆?您将如何实现它以便它可以处理任何对象,无论是大的、嵌套的还是小的?

【问题讨论】:

  • 请添加您尝试过的和无效的。
  • 它也不应该包含具有对象/数组值的键 - 但在您的示例 B 中,check_params 被添加到列表中,即使它的值是对象。
  • @tymeJV Expected output 仅包含 check_params.basic_authcheck_params.encryption.enabled(嵌套键),而不包含具有对象值的 check_params 本身。

标签: javascript arrays object recursion javascript-objects


【解决方案1】:

你可以像这样使用 reduce:

const keyify = (obj, prefix = '') => 
  Object.keys(obj).reduce((res, el) => {
    if( Array.isArray(obj[el]) ) {
      return res;
    } else if( typeof obj[el] === 'object' && obj[el] !== null ) {
      return [...res, ...keyify(obj[el], prefix + el + '.')];
    }
    return [...res, prefix + el];
  }, []);

const input = {
   "check_id":12345,
   "check_name":"Name of HTTP check",
   "check_type":"HTTP",
   "tags":[
     "example_tag"
   ],
   "check_params":{
      "basic_auth":false,
      "params":[
        "size"
      ],
      "encryption": {
        "enabled": true,
        "testNull": null,
      }
   }
};

const output = keyify(input);

console.log(output);

Edit1:对于您想要包含数组的一般情况。

const keyify = (obj, prefix = '') => 
  Object.keys(obj).reduce((res, el) => {
    if( typeof obj[el] === 'object' && obj[el] !== null ) {
      return [...res, ...keyify(obj[el], prefix + el + '.')];
    }
    return [...res, prefix + el];
  }, []);

const input = {
   "check_id":12345,
   "check_name":"Name of HTTP check",
   "check_type":"HTTP",
   "tags":[
     "example_tag"
   ],
   "nested": [
      { "foo": 0 },
      { "bar": 1 }
   ],
   "check_params":{
      "basic_auth":false,
      "params":[
        "size"
      ],
      "encryption": {
        "enabled": true,
        "testNull": null,
      }
   }
};

const output = keyify(input);

console.log(output);

【讨论】:

  • @NinaScholz 你的意思是如果input 对象是null
  • 可能你把enabled的值从true改成null,然后就不行了,因为你少了一张支票。
  • 当我们要返回所有键时,我有一个类似的问题,请添加这个对象 { a: 1, b: 2, c: ["a", "b", "c"], z: { a: "j", q: "q" } 它会返回 ["a", "b", "za", "zq"],我怎样才能显示像 c 这样的所有键?
  • @YasinFarmani 看看我回答的结尾。 “Edit1:对于您想要包含数组的一般情况。”
【解决方案2】:

这是你的意思吗?

http://jsfiddle.net/robbiemilejczak/hfe12brb/1/

我不能用 vanilla JS 做到这一点,这是一个依赖 lodash 的非常 hacky 的解决方案。基本上利用 lodashs _.forIn_.isArray 函数来迭代对象。此外,这只会深入 1 层,因此嵌套对象内的对象将被忽略。不过,它确实会产生您预期的输出,所以我认为这是一个不错的起点。

【讨论】:

    【解决方案3】:

    您可以使用for...in 并创建递归函数。

    var obj = {"check_id":12345,"check_name":"Name of HTTP check","check_type":"HTTP","tags":["example_tag"],"check_params":{"basic_auth":false,"params":["size",{"a":"b"}],"encryption":{"enabled":true}}}
    
    var keys = []
    function getKeys(data, k = '') {
      for (var i in data) {
        var rest = k.length ? '.' + i : i
    
        if (typeof data[i] == 'object') {
          if (!Array.isArray(data[i])) {
            getKeys(data[i], k + rest)
          }
        } else keys.push(k + rest)
      }
    }
    
    getKeys(obj)
    console.log(keys)

    【讨论】:

    • 具有像全局 keys 变量这样明显不必要的副作用可能会向新的 JS 程序员传达错误的信息。只是一个想法。
    【解决方案4】:

    您可以检查键并进行迭代,否则将路径推送到结果集。

    function getKeys(object) {
        function iter(o, p) {
            if (Array.isArray(o)) { return; }
            if (o && typeof o === 'object') {
                var keys = Object.keys(o);
                if (keys.length) {
                    keys.forEach(function (k) { iter(o[k], p.concat(k)); });
                }
                return;
            }
            result.push(p.join('.'));
        }
        var result = [];
        iter(object, []);
        return result;
    }
    
    var object = { check_id: 12345, check_name: "Name of HTTP check", check_type: "HTTP", tags: ["example_tag"], check_params: { basic_auth: false, params: ["size"], encryption: { enabled: true } } };
    
    console.log(getKeys(object));
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

      【解决方案5】:

      生成器可以快速解决此类问题 -

      function* deepKeys (t, pre = [])
      { if (Array.isArray(t))
          return
        else if (Object(t) === t)
          for (const [k, v] of Object.entries(t))
            yield* deepKeys(v, [...pre, k])
        else
          yield pre.join(".")
      }
      
      const input =
        {check_id:12345,check_name:"Name of HTTP check",check_type:"HTTP",tags:["example_tag"],check_params:{basic_auth:false,params:["size"],encryption:{enabled:true,testNull:null,}}}
       
      console.log(Array.from(deepKeys(input)))
      [ "check_id"
      , "check_name"
      , "check_type"
      , "check_params.basic_auth"
      , "check_params.encryption.enabled"
      , "check_params.encryption.testNull"
      ]
      

      或者是一个急切地计算所有键的纯函数表达式 -

      const deepKeys = (t, pre = []) =>
        Array.isArray(t)
          ? []
      : Object(t) === t
         ? Object
            .entries(t)
            .flatMap(([k, v]) => deepKeys(v, [...pre, k]))
      : pre.join(".")
      
      const input =
        {check_id:12345,check_name:"Name of HTTP check",check_type:"HTTP",tags:["example_tag"],check_params:{basic_auth:false,params:["size"],encryption:{enabled:true,testNull:null,}}}
       
      console.log(deepKeys(input))
      [ "check_id"
      , "check_name"
      , "check_type"
      , "check_params.basic_auth"
      , "check_params.encryption.enabled"
      , "check_params.encryption.testNull"
      ]
      

      【讨论】:

        【解决方案6】:

        var json = {
            id: '1234',
            test: 'terst',
            user : {
                name: '',
                details: {
                    address: {
                            add2: {
                                prim: "",
                                sec: ""
                            },
                            add1: '',
                    }
                }
            },
            salary: {
              cur: 1234,
              net: 89797
            },
            age: 12
        }
        
        let arr = [];
        let initialObj = {};
        
        function getKeys(obj, parentK=''){
          initialObj = arr.length === 0 ? obj: initialObj;
          const entries = Object.entries(obj);
          for(let i=0; i<entries.length; i++) {
            const key = entries[i][0];
            const val = entries[i][1];
            const isRootElement = initialObj.hasOwnProperty(key);
            parentK = isRootElement ? key: parentK+'.'+key;
            arr.push(parentK)
            if(typeof val === 'object' && val!==null && !Array.isArray(val)){
              getKeys(val, parentK);
            }
          }
        }
        
        getKeys(json)
        
        console.log('arr final---', arr);

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-12-14
          • 1970-01-01
          • 1970-01-01
          • 2023-01-17
          • 2020-07-20
          • 2016-10-31
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多