【问题标题】:Get all unique object properties from array of objects从对象数组中获取所有唯一的对象属性
【发布时间】:2017-01-07 23:45:12
【问题描述】:

假设我有一个对象数组,例如

 [{
    "firstName": "John",
    "lastName": "Doe"
 }, {
    "firstName": "Anna",
    "car": true
 }, {
    "firstName": "Peter",
    "lastName": "Jones"
 }]

我想从这个对象数组中获取所有唯一的属性名称,所以结果将是:

[firstName, lastName, car]

我该怎么做:

我可以想象用这样的方式来做到这一点是可能的:

function getPropertiesNames(obj){
  var arr = [];
  for(var name in obj) {
    if(arr.indexOf(name) != -1) arr.push(name);
  }
 return arr;
} 

我为什么需要它:

我必须制作一个包含多个对象的表格。因为每个对象都可能有点不同,所以我需要唯一的属性名称。但是我将在 angularJS 中执行此操作,因此对于我来说,一次使用循环获取 <th> 的属性名称并再次使用循环与 <tr ng-repeat></tr> 来显示值对我来说是一个糟糕的选择。

我想要什么:

是否有一些选项可以从对象数组中获取所有唯一属性名称而不对其进行迭代?也许是一些我不知道的 lodash 或内置 JS 函数?

【问题讨论】:

    标签: javascript angularjs arrays object lodash


    【解决方案1】:

    仅使用的解决方案:

    var data = [{
      "firstName": "John",
      "lastName": "Doe"
    }, {
      "firstName": "Anna",
      "car": true
    }, {
      "firstName": "Peter",
      "lastName": "Jones"
    }];
    
    var uniqueKeys = Object.keys(data.reduce(function(result, obj) {
      return Object.assign(result, obj);
    }, {}))
    
    console.log(uniqueKeys);

    【讨论】:

    • 您好,谢谢您的回答。它看起来更具可读性。但是,我可以问您与常规循环或此问题的答案相比,它是否会更快?
    • 它不会比常规循环快。我不确定是否有显着差异。使用这些标准方法的主要好处是它们是安全的(因为它们遵循 js 标准),并且易于阅读和理解。查看链接文章中的 polyfill,了解它们在幕后所做的工作。
    【解决方案2】:

    您可以使用map()keys() 返回每​​个对象的键,然后使用union()flatten()

    var data = [{
      "firstName": "John",
      "lastName": "Doe"
    }, {
      "firstName": "Anna",
      "car": true
    }, {
      "firstName": "Peter",
      "lastName": "Jones"
    }]
    
    var result = _.union(_.flatten(_.map(data, (e) => _.keys(e))));
    console.log(result)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

    【讨论】:

    • 感谢您回答@NenadVracar,我有两个问题。 1. 这是什么:... 是什么意思? 2. 与我的选项或 Tholle 的选项相比,有关性能的任何想法
    • 即展开操作符,你可以使用 flatten 代替,就像在更新中一样。
    • 你也可以像这样使用uniqvar result = _.uniq(_.flatten(_.map(data, (e) => _.keys(e))));
    • 谢谢,请不要犹豫,将其添加到您的答案中:) 我喜欢有多种选择。与我的代码或以下其他 ppl 的代码相比,您对所有这些选项的速度有任何了解吗?
    • 您不需要将_.keys() 包装在箭头函数中。像这样传递它:_.map(data, _.keys)
    【解决方案3】:

    我认为您无法避免检查每个对象中的每个键。您可以使用例如 reduce:

    来完成它
    var result = _.reduce(array, function(memory, obj) {
      for (var key in obj) {
        if(memory.indexOf(key) === -1) memory.push(key)
      }
      return memory;
    }, []);
    

    var array = [{
      "firstName": "John",
      "lastName": "Doe"
    }, {
      "firstName": "Anna",
      "car": true
    }, {
      "firstName": "Peter",
      "lastName": "Jones"
    }];
    
    var result = _.reduce(array, function(memory, obj) {
      for (var key in obj) {
        if(memory.indexOf(key) === -1) memory.push(key)
      }
      return memory;
    }, []);
    
    console.log(result);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

    或者,您可以将密钥存储在一个新对象中,然后提取密钥:

    var temp = _.reduce(array, function(memory, obj) {
      for (var key in obj) {
        memory[key] = null;
      }
      return memory;
    }, {});
    var result = Object.keys(temp);
    

    var array = [{
      "firstName": "John",
      "lastName": "Doe"
    }, {
      "firstName": "Anna",
      "car": true
    }, {
      "firstName": "Peter",
      "lastName": "Jones"
    }];
    
    var temp = _.reduce(array, function(memory, obj) {
      for (var key in obj) {
        memory[key] = null;
      }
      return memory;
    }, {});
    var result = Object.keys(temp);
    
    console.log(result);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

    【讨论】:

    • 感谢@Tholle 的回答,请问使用这个而不是经典循环有什么好处?我敢打赌我错过了一些东西,但从文档中它听起来像经典循环
    • @Andurit 不客气!如果您有一个大数组,则常规循环可能会更快。如果您有一个小数组,并且像我一样发现 reduce 更具可读性,您可能会选择其中一种解决方案。
    【解决方案4】:

    您可以使用Object.assign()spread syntax 将对象数组合并为单个对象。然后从合并的对象中获取键:

    Object.keys(Object.assign({}, ...array)) 
    

    这是一个sn-p:

    const array = [{firstName:"John",lastName:"Doe"},{firstName:"Anna",car:true},{firstName:"Peter",lastName:"Jones"}],
          unique = Object.keys(Object.assign({}, ...array))
    
    console.log(unique)

    另一种选择是使用Object.keys 作为flatMap 的回调。这将返回 所有 个键的数组。然后,创建一个Set 以获取唯一键并使用Array.from() 将集合转换为数组。

    const keys = input.flatMap(Object.keys),
          unique = Array.from(new Set(keys));
    

    这是一个有效的 sn-p:

    const input=[{firstName:"John",lastName:"Doe"},{firstName:"Anna",car:true},{firstName:"Peter",lastName:"Jones"}],
          unique = Array.from(new Set(input.flatMap(Object.keys)));
    
    console.log(unique)

    如果flatMap不支持,可以使用

    const keys = [].concat(...input.map(Object.keys)),
    

    【讨论】:

      【解决方案5】:

      你也可以试试这个:

      var source = [{
      "firstName": "John",
      "lastName": "Doe"
       }, {
      "firstName": "Anna",
      "car": true
       }, {
      "firstName": "Peter",
      "lastName": "Jones"
       }];
      
      uniq(source);
      
      function uniq(source){
         var result = source.reduce(function(p, c) {
      
           Object.keys(c).forEach(function(key) {
               p[key] = true;
           });
      
           return p;
          }, {});
      
          return Object.keys(result);
      }
      

      【讨论】:

        【解决方案6】:

        你可以用这个:

        var result = [];
        array.reduce( function(pre, item) {
            Object.keys(item).forEach(function(i){
                if (result.indexOf(i) === -1){
                    result.push(i);
                }
            });
        });
        

        var array = [{
          "firstName": "John",
          "lastName": "Doe"
        }, {
          "firstName": "Anna",
          "car": true
        }, {
          "firstName": "Peter",
          "lastName": "Jones"
        }];
        
        var result = [];
        array.reduce( function(pre, item) {
            Object.keys(item).forEach(function(i){
                if (result.indexOf(i) === -1){
                    result.push(i);
                }
            });
        });
        
        console.log(result);

        【讨论】:

          【解决方案7】:

          我的解决方案没有任何库。

          var array = [{
            "firstName": "John",
            "lastName": "Doe"
          }, {
            "firstName": "Anna",
            "car": true
          }, {
            "firstName": "Peter",
            "lastName": "Jones"
          }];
          
          var arr = [],merged,uniqArray;
          
          array.forEach(function(val){ //Getting all properties
             arr.push(Object.keys(val))
           });
          
          merged = [].concat.apply([], arr);//Merging all array to single array
          
          merged.forEach(function(val){
            if(uniqArray.indexOf(val)== -1){// Getting uniqe values
             uniqArray.push(val)
          }})
          

          结果

          ["firstName", "lastName", "car"]
          

          【讨论】:

            【解决方案8】:

            一个班轮选项:

            [...new Set(a.map(Object.keys).reduce((a, b) => a.concat(b)))];
            

            【讨论】:

            • 我看到有人不喜欢它。
            【解决方案9】:

            使用平面的替代方法

            const arr = 
            [{
                "firstName": "John",
                "lastName": "Doe"
             }, {
                "firstName": "Anna",
                "car": true
             }, {
                "firstName": "Peter",
                "lastName": "Jones"
             }].map(obj => Object.getOwnPropertyNames(obj)).flat()
            const s = [...new Set(arr)]
            console.log(s) 

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2018-12-05
              • 2018-11-14
              • 1970-01-01
              • 2022-01-10
              • 2018-05-25
              • 1970-01-01
              • 2019-05-20
              • 2022-10-19
              相关资源
              最近更新 更多