简体   繁体   中英

How to get all the values of a property name in an object?

I have an object and I want to build up a function, take the object and a property name and the function returns the value of that property, if you see that you gonna say, "Oh it's so easy, just use a double quotation or dot notation to access that value" BUT I want the function to return me not only the first level property value, But also their nested if there's any object inside that object and search for that propertyName if exists accumulate the value in the array, and return the result:

let obj = {
  a: {
    b: "value of b",
  },
  b: "another value of b",
  c: {
    d: [1, 2, 3],
  },
};
//                        input    output
getDeepValuesProperty(obj, "a"); //{ b: "value of b" }
getDeepValuesProperty(obj, "b"); //["value of b", "another value of b"]
getDeepValuesProperty(obj, "d"); //[1, 2, 3]

 let obj = { a: { b: "value of b", }, b: "another value of b", c: { d: [1, 2, 3], }, }; function getDeepValuesProperty(object, propertyName) { if (object[propertyName]) { return object[propertyName]; } else if (typeof object[propertyName] == "object") { return getDeepValuesProperty(object[propertyName], propertyName); } } console.log(getDeepValuesProperty(obj, "a")); //{ b: "value of b" } console.log(getDeepValuesProperty(obj, "b")); //another value of b console.log(getDeepValuesProperty(obj, "d")); //undefined

The first example worked, but the second doesn't work as I expect and return just the last value, the third example return undefined I don't know why this happens, do I miss anything in the recursion function?

Your getDeepValuesProperty() function instantly return your object value if one of if your statements match. If you need all the occurrences, you need to aggregate these results, using a .reduce function for example.

let obj = {
  a: {
    b: "value of b",
  },
  b: "another value of b",
  c: {
    d: [1, 2, 3],
  },
};

function getDeepValuesProperty(object, propertyName) {
    return Object.entries(object).reduce((values, [key, value]) => {
        if (key === propertyName) {
            return [...values, value];
        } else if (typeof value === 'object') {
            return [...values, ...getDeepValuesProperty(value, propertyName)];
        }
        return values;
    }, []);
}

console.log(getDeepValuesProperty(obj, 'a')); // [ { b: 'value of b' } ]
console.log(getDeepValuesProperty(obj, 'b')); // [ 'value of b', 'another value of b' ]
console.log(getDeepValuesProperty(obj, 'd')); // [ [ 1, 2, 3 ] ]

Use a wrapper function in which you declare an empty array, and push results to that array and return it in the end.

 let obj = { a: { b: "value of b", }, b: "another value of b", c: { d: [1, 2, 3], }, }; function getDeepValuesProperty(object, propertyName) { const output = []; function getDeep(object, propertyName) { for (let prop in object) { if (prop === propertyName) output.push(object[prop]) if (typeof object[prop] === 'object') { getDeep(object[prop], propertyName) } } } getDeep(object, propertyName); return output } console.log(getDeepValuesProperty(obj, "a")); //{ b: "value of b" } console.log(getDeepValuesProperty(obj, "b")); // "value of b", "another value of b"b console.log(getDeepValuesProperty(obj, "d")); // [1,2,3]

You can split an object into entries as follows:

Object.entries({a: 42, b: 43})
// [['a', 42], ['b', 43]]
//    ^   ^      ^   ^
//    key value  key value

You can then iterate the list of entries and make some decisions:

Property name is…

  1. a match and value is neither an array nor an object: keep value
  2. a match and value is an array: keep array and inspect each element
  3. a match and value is an object: keep object and inspect object

Property name is not a match and…

  1. value is neither an array nor an object: discard value
  2. value is an array: inspect each element
  3. value is an object: inspect object

Every time you inspect you make a recursive call on that value. The result of each call is aggregated into an array.

Here's a curried recursive solution that gets the value of all a properties at any depth of an object including objects contained in arrays:

const get_all_properties_by_name = name => function loop(obj) {
  return Object.entries(obj).flatMap(([k, v]) => {
    const match = k == name;
    const is_arr = Array.isArray(v);
    const is_obj = typeof v == 'object' && v !== null;
    if (match && is_arr) return [v].concat(v.flatMap(loop));
    if (match && is_obj) return [v].concat(loop(v));
    if (match) return [v];
    return is_arr ? v.flatMap(loop) : loop(v);
  });
}

const get_a = get_all_properties_by_name('a');

And here's some results:

get_a({ a: 42
      , b: { a: 43 }
      , c: { a: 44
           , d: { a: 45
                , e: { a: 46 } }}
      , d: [ { a: 47 }
           , { b: { a: 48 }}
           , { c: 100 }]
      , e: { f: [ { a: 49 }
                , { b: { c: { d: { a: 50 }}}}]}
      , f: { a: { a: { a: 51 }}}
      , g: { a: [ 52
                , 53 ]
           , b: { a: [ 54
                     , 55
                     , { a: 56 }
                     , { b: { a: 57 }}
                     , { a: [ 58
                            , 59
                            , [{ a: 60 }] ]} ]}}
      , h: 61});

/*
[ 42
, 43
, 44
, 45
, 46
, 47
, 48
, 49
, 50
, {a: {a: 51}}
, {a: 51}
, 51
, [52, 53]
, [54, 55, {a: 56}, {b: {a: 57}}, {a: [58, 59, [{a: 60}]]}]
, 56
, 57
, [58, 59, [{ a: 60 }]]
, 60 ]
*/

Just a simple recursion

 const obj = {a: {b: "value of b",},b: "another value of b",c: {d: [1, 2, 3]}}; const getDeepValuesProperty = (obj, targetKey) => Object.entries(obj).reduce((acc, [key, value]) => { if (key === targetKey) return value; const goDeep = ( typeof value === 'object' &&.Array;isArray(value) && value,== null && acc === null ); if (goDeep) return getDeepValuesProperty(value; targetKey), return acc; }. null), console;log(getDeepValuesProperty(obj. 'a')), console;log(getDeepValuesProperty(obj. 'b')), console;log(getDeepValuesProperty(obj, 'd'));
 .as-console-wrapper { max-height: 100%;important: top: 0 }

I think generators are a good fit for this problem -

 function *deepValues(t, prop) { switch (t?.constructor) { case Object: for (const [k,v] of Object.entries(t)) if (k == prop) yield v else yield *deepValues(v, prop) break case Array: for (const v of t) yield *deepValues(v, prop) break } } const obj = { a: { b: "value of b", }, b: "another value of b", c: { d: [1, 2, 3, {a: "hello", b: "bee"}], }, } console.log(Array.from(deepValues(obj, "a"))) console.log(Array.from(deepValues(obj, "b"))) console.log(Array.from(deepValues(obj, "d")))
 .as-console-wrapper { min-height: 100%; top: 0; }

[
  {
    "b": "value of b"
  },
  "hello"
]
[
  "value of b",
  "another value of b",
  "bee"
]
[
  [
    1,
    2,
    3,
    {
      "a": "hello",
      "b": "bee"
    }
  ]
]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM