How to get all keys with values from nested objects

余生长醉 提交于 2019-12-30 23:50:32

问题


I'm looking for something kind of like Object.keys but that works for potentially nested objects. It also shouldn't include keys that have object/array values (it should only include keys with immediate string/number/boolean values).

Example A

Input

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

Expected output

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

Object.keys would work for flat cases like this, but not for nested cases:

Example B

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,
      }
   }
}

Expected output

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

Note that this does not include tags, check_params, check_params.params, or check_params.encryption since these values are arrays/objects.

The question

Is there a library that does this? How would you implement it so that it can work with any object, large and nested, or small?


回答1:


You could use reduce like this:

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 + '.')];
    } else {
      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);



回答2:


You could check the keys and iterate otherwise push the path to the result set.

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; }



回答3:


You can use for...in and create recursive function.

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)



回答4:


Here's one way you can do it

const isPlainObject = x =>
  Object (x) === x && ! Array.isArray (x)

const formatKey = (...segments) =>
  segments .join ('.')

const deepKeys = (o, pre = [], acc = []) =>
  Object
    .keys (o)
    .reduce
      ( (acc, k) =>
          isPlainObject (o [k])
            ? [ ...acc, ...deepKeys (o [k], [ ...pre, k ], acc) ]
            : [ ...acc, formatKey (...pre, k) ]
      , []
      )

const data =
  { a: 1
  , b: 2
  , c: { d: 3
       , e: [ 4, 'a', 'b', 'c' ]
       , f: { g: 5
            , h: 6 
            } 
       }
  }
 
console .log (deepKeys (data))
// [ 'a'
// , 'b'
// , 'c.d'
// , 'c.e'
// , 'c.f.g'
// , 'c.f.h'
// ]



回答5:


Is this what you mean?

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

I couldn't do it with vanilla JS, and this is a pretty hacky solution that relies on lodash. Basically leverages lodashs _.forIn and _.isArray functions to iterate over an object. Also this will only go 1 layer deep, so objects inside of nested objects will be ignored. It does produce your expected output though, so I'd say it's a decent starting point.



来源:https://stackoverflow.com/questions/47062922/how-to-get-all-keys-with-values-from-nested-objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!