如何在JS中获取对象数组的特定属性?

时间:2018-09-27 16:08:47

标签: javascript arrays

我有以下代码和测试数据:

const getNestedObject = (nestedObj, pathArr) => {
    return pathArr.reduce((obj, key) => {
        return (obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj;
    });
}

const obj = 
 [
  {
      a: 1,
      c: [
        {
          d: 1,
          e: 'string',
          f: [
            {
              value: 0,
            },
            {
              value: 1,
            }
          ],
        },
      ],
  },
    {
      a: 2,
      c: [
        {
          d: 2,
          e: 'string',
          f: [
            {
              value: 3,
            },
            {
              value: 4,
            }
          ],
        },
      ],
  },
 ];

console.log(obj);
const fs = obj.map(o => getNestedObject(o, ['c', 'f']));
console.log(fs);

我要给定的对象数组如下所示,我想从数组中的每个对象中仅获取名为f的属性。因此,基本上,最终结果应该是每个对象的f值数组。由于“ f”是一个数组,因此,我非常希望最终结果是一个包含所有“ f”属性中的元素的数组,因此,每种“ f”都应散布,因此我只有一个数组。我上面的getNestedObject函数似乎不起作用,因为下面的console.log语句返回了整个对象。有什么想法在JS中做到这一点吗?

所以基本上,最终结果应该是:

[{ value: 0 }, { value: 1 }, { value: 3 }, {value: 4 }]

4 个答案:

答案 0 :(得分:4)

您可以将reduce()map()结合使用。基本上将主数组简化为所有c.f项的扁平数组。这将检查c属性,以防万一对象没有该属性:

const obj = [{a: 1,c: [{d: 1,e: 'string',f: [{value: 0,},{value: 1,}],},],},{a: 2,c: [{d: 2,e: 'string',f: [{value: 3,},{value: 4,}],},],},];

let Fs = obj.reduce((arr, item) => 
    item.c
    ? arr.concat(...item.c.map(itemc => itemc.f ))  // concat for flattened rather than nested arrays
    : arr
    , []);

console.log(Fs)

答案 1 :(得分:1)

这是一个快速的迭代解决方案,不会溢出堆栈,不对目标结果值是数组进行任何假设(如果存在则仅进行扩展),并且不对子键名进行硬编码(它将探索任何会是数组)。

如果目标的子项与您要包含在搜索中的键匹配(将else ifif交换),这也可以工作。

const get = (data, target) => {
  const result = [];
  const stack = [data];
  
  while (stack.length) {
    const curr = stack.pop();
    
    for (const o of curr) {
      for (const k in o) {
        if (k === target) {
          if (Array.isArray(o[k])) {
            result.push(...o[k]);
          }
          else {
            result.push(o[k]);
          }
        }
        else if (Array.isArray(o[k])) {
          stack.push(o[k]);
        }
      }
    }
  }
  
  return result;
};
 
const obj = 
[
  {
      a: 1,
      c: [
        {
          d: 1,
          e: 'string',
          f: [
            {
              value: 0,
            },
            {
              value: 1,
            }
          ],
        },
      ],
  },
    {
      a: 2,
      c: [
        {
          d: 2,
          e: 'string',
          f: [
            {
              value: 3,
            },
            {
              value: 4,
            }
          ],
        },
      ],
  },
 ];
 
 console.log(get(obj, "f"));

答案 2 :(得分:1)

您可以递归地遍历任何对象和数组以获取给定的属性。这在任何深度都有效,并且与对象的结构无关:

const obj=[{a:1,c:[{d:1,e:"string",f:[{value:0},{value:1}]}]},{a:2,c:[{d:2,e:"string",f:[{value:3},{value:4}]}]}];

//curried function to grab a property by name off some object or array
function grab(prop) {
  //naming the inner function means it can be called recursively by name
  return function recursiveGrab(target) {
    if (Array.isArray(target)) {
      const arrayResult = target
          .filter(x => typeof x === "object") //remove non-objects (and non-arrays)
          .filter(Boolean) //remove null
          .map(recursiveGrab); //recursively call for the remaining objects 
      return flatten(arrayResult); //return a single dimensional array
    }
    
    //an object has the property - return it
    if (prop in target) {
      return target[prop];
    }
    
    //object doesn't have the property - check all values
    return recursiveGrab(Object.values(target));
  }
}

//small helper function. It's separated only to keep the logic for the traversal clear
function flatten(arr) {
  return arr.reduce((acc, curr) => acc.concat(curr), [])
}

const grabF = grab('f');

console.log(grabF(obj));

答案 3 :(得分:0)

我没有注意到f始终在c内部。我有一个可以在任何字段中使用f的递归且肮脏的解决方案

        const objArray = [
          {
              a: 1,
              c: [
                {
                  d: 1,
                  e: 'string',
                  f: [
                    {
                      value: 0,
                    },
                    {
                      value: 1,
                    }
                  ],
                },
              ],
             d: [
                {
                  d: 1,
                  e: 'string',
                  f: [
                    {
                      value: 'd',
                    },
                    {
                      value: 'd1',
                    }
                  ],
                },
              ],
          },
            {
              a: 2,
              c: [
                {
                  d: 2,
                  e: 'string',
                  f: [
                    {
                      value: 3,
                    },
                    {
                      value: 4,
                    }
                  ],
                },
              ],
              e: [
                {
                  d: 1,
                  e: 'string',
                  f: [
                    {
                      value: 'e',
                    },
                    {
                      value: 'e1',
                    }
                  ],
                },
              ],
            }
        ]
         
         
         const getFObject = (obj) => {
           let fObj = [];
           Object.keys(obj).some(key => {
             if (key === 'f') {
               fObj = obj[key];
               return true;
             }
             if (Array.isArray(obj[key])) {
               obj[key].forEach(nestedObj => {
                 fObj = fObj.concat(getFObject(nestedObj))
               });
             }
             return false;
           });
           return fObj;
         }
         
         const newArray = objArray.reduce((acc, obj) => {
           return acc.concat(getFObject(obj))
         }, []);
         console.log(newArray)