从对象数组中获取所有唯一的对象属性

Posted

技术标签:

【中文标题】从对象数组中获取所有唯一的对象属性【英文标题】: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 函数?

【问题讨论】:

【参考方案1】:

仅使用的解决方案:

Object.assign Object.keys Array.prototype.reduce

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) 

【讨论】:

以上是关于从对象数组中获取所有唯一的对象属性的主要内容,如果未能解决你的问题,请参考以下文章

获取嵌套数组/对象的数组中的所有唯一值(删除重复项)

从嵌套属性数组中获取对象嵌套值

如何使用把手 (hbs) 迭代嵌套数组和对象?

如何从 jquery 对象映射中过滤唯一的数据属性值

从ios中的数组获取完整的对象

TS / JS-如果对象的属性与数组中的另一个属性相匹配,则从对象数组中获取“值”