【问题标题】:dynamically flatten nested array of objects javascript动态展平嵌套的对象数组javascript
【发布时间】:2020-07-11 14:51:03
【问题描述】:

我正在尝试编写一个接受嵌套对象数组并动态返回展平结果的函数。 arrayProperties.filter() 没有像我期望的那样返回对象数组。

const data = [ 
    {
        parKeyA: "parValA",
        parKeyA1:
            {chiKeyA1: "chiValA1", chiKeyA2: "chiValA2"},
        parKeyA2: {chiKeyA3: "chiValA3"}
    },
    {
        parKeyB: "parValB",
        parKeyB1:
            {chiKeyB1:"chiValB1"}
    }
]

flatData = flatNestedObjArray(data);
console.log(flatData);

function flatNestedObjArray(array) {
    let flatArray = array.map(element => {
        let arrayProperties = Object.entries(element);
        //filter not returning array of objects
        let nestedObjects = arrayProperties.filter(property => {
            const parentValue = property[1];
            if (typeof parentValue === "object" && parentValue !== null) {
                return parentValue;
            }
        });
        //nestedObjects should be array of objects
        let merged = nestedObjects.map(obj => element.concat(obj));
        return merged;
    });
    return flatArray;
}

预期结果:

const data = [ 
    {
        parKeyA: "parValA",
        chiKeyA1: "chiValA1",
        chiKeyA2: "chiValA2",
        chiKeyA2: "chiValA2"
    },
    {
        parKeyB: "parValB",
        chiKeyB1:"chiValB1"
    }
]

【问题讨论】:

  • Flatten 与数组而非对象有关。前任。 [1, 2, 3] 变平为 1, 2, 3。此外,具有重复键的对象无效。前任。 chiKeyA2 在第一个对象中出现两次。
  • @zer00ne 修复了 dup 键...你会怎么称呼它?另外,您对如何解决问题有任何帮助吗?
  • 看看你所期望的......模式如下所示: 1. 对象中的每个对象都必须将它们的键/值移动到父对象。 2. 然后删除空对象。这没有多大意义......但如果这是你真正想要的,有办法做到这一点。我会发布一个答案。
  • 感谢您的回答都很好,选择的答案有点短!

标签: javascript arrays nested-object


【解决方案1】:

Object.entries() 获取一个对象并将其转换为二维数组:

let object = {keyA: "valueA", keyB: "valueB", keyC: {kA: "vA", kB: "vB"}};
let array = Object.entries(object);
// array = [["keyA", "valueA"], ["keyB", "valueB"], ["keyC", {kA: "vA", kB: "vB"}]];

for...of 循环中使用上述内容,可以解构每个条目:

for (let [key, value] of Object.entries(object)) {...

  1. 声明一个空数组并遍历对象数组中的每个对象字面量:

    let array = [];
    for (let obj of objArray) {...
    
  2. 在每个对象上,声明一个空对象,然后将每个对象的每个键/值转换成一个子数组:

    let object = {};
    for (let [key, value] of Object.entries(obj)) {...
    
  3. 检查每个对象字面量的每个值——如果该值是对象字面量...

    if (Object.prototype.toString.call(value) == "[object Object]") {...
    
  4. ...遍历值并将每个键/值分配给空对象...

    for (let [k, v] of Object.entries(value)) {
      object[k] = v;
    }
    
  5. ...否则将键/值分配给空对象...

    } else {
      object[key] = value;
    }
    
  6. 将新对象推送到新数组中:

    array.push(object);
    

演示

const data = [{
    parKeyA: "parValA",
    parKeyA1: {
      chiKeyA1: "chiValA1",
      chiKeyA2: "chiValA2"
    },
    parKeyA2: {
      chiKeyA3: "chiValA3"
    }
  },
  {
    parKeyB: "parValB",
    parKeyB1: {
      chiKeyB1: "chiValB1"
    }
  }
];

function subObjToKeyVal(objArr) {
  let array = [];
  for (let obj of objArr) {
    let object = {};
    for (let [key, value] of Object.entries(obj)) {
      if (Object.prototype.toString.call(value) == "[object Object]") {
        for (let [k, v] of Object.entries(value)) {
          object[k] = v;
        }
      } else {
        object[key] = value;
      }
    }
    array.push(object);
  }
  return array;
}

console.log(subObjToKeyVal(data));

【讨论】:

    【解决方案2】:

    您可以使用map,它将返回一个数组和一个递归函数。已在代码中添加注释,希望对您有用

    const data = [{
        parKeyA: "parValA",
        parKeyA1: {
          chiKeyA1: "chiValA1",
          chiKeyA2: "chiValA2"
        },
        parKeyA2: {
          chiKeyA3: "chiValA2"
        }
      },
      {
        parKeyB: "parValB",
        parKeyB1: {
          chiKeyB1: "chiValB1"
        }
      }
    ]
    /* Recursive function.It will take a object,iterate the object and check if the value of the key is another object. If it is another object then call same recursive function  */
    function getFlatObj(obj) {
      let newObject = {}
    
      function doRecurssion(currObj) {
        // iterate through the object
        for (let keys in currObj) {
          // check if the value is another object 
          if (typeof currObj[keys] === 'object' && typeof currObj[keys] !== null) {
            doRecurssion(currObj)
          } else {
            // if not another object then add key and value
            newObject[keys] = currObj[keys]
    
          }
        }
        return newObject;
      }
    
      return doRecurssion(obj);
    }
    
    let flatObj = data.map((item) => {
      const acc = {};
      for (let keys in item) {
        if (typeof item[keys] === 'object' && typeof item[keys] !== null) {
          Object.assign(acc, getFlatObj(item[keys]))
        } else {
          acc[keys] = item[keys]
        }
      }
    
      return acc;
    }, {});
    
    console.log(flatObj)

    【讨论】:

      【解决方案3】:

      您可以使用递归将对象展平为单层对象,并将该函数传递给 map 以获得展平对象的数组

      const data = [{
          parKeyA: "parValA",
          parKeyA1: {
            chiKeyA1: "chiValA1",
            chiKeyA2: "chiValA2"
          },
          parKeyA2: {
            chiKeyA3: "chiValA3"
          }
        },
        {
          parKeyB: "parValB",
          parKeyB1: {
            chiKeyB1: "chiValB1",
            chiKeyB2: {}
          }
        }
      ]
      
      
      let flatten = (obj, final = {}) => {
        for (let key in obj) {
          if (typeof obj[key] === 'object' && obj[key] != null) {
            flatten(obj[key], final)
          } else {
            final[key] = obj[key]
          }
        }
        return final
      }
      
      console.log(data.map((v) => flatten(v)))

      【讨论】:

      • 谢谢。这是一个非常简单直接的答案。我一直在寻找这样的东西。非常感谢
      【解决方案4】:

      您可以使用 in 关键字在每个级别使用递归来使用对象属性循环

      for(var prop in data) {
          ....
      }
      

      我使用一种旧的递归技术来开始工作代码

      function flatten(data) {
          var newData = {};
          for(var prop in data) {
              if(typeof data[prop] == "object") {
                  var childs = flatten(data[prop])
                  for(var cprop in childs){
                      newData[cprop] = childs[cprop];
                  }
              }else {
                  newData[prop] = data[prop]
              }
          }
          return newData;
      }
      
      for(var i=0;i<data.length;i++)
         data[i] = flatten(data[i]);
      
      console.log(data);
      

      您需要处理重复项

      【讨论】:

      • 使用Array.map()除了变量赋值有很大区别吗?
      • 这段代码在我的机器上工作,我希望它可以帮助你从这个开始,然后用地图或过滤器来增强它
      • @BrettB 没有太大区别,唯一的区别是赋值会修改原始传递的数组,而当您使用 map 时,它将创建一个新数组。
      猜你喜欢
      • 1970-01-01
      • 2020-12-22
      • 2020-06-23
      • 1970-01-01
      • 1970-01-01
      • 2021-03-22
      • 1970-01-01
      • 2018-04-20
      • 2019-07-20
      相关资源
      最近更新 更多