从对象数组获取唯一值

时间:2019-02-28 14:11:03

标签: javascript unique

我有一个这样的动态对象数组:

var arr = [
    {state: "FL"},
    {state: "NY"},
    {state: "FL"},
    {gender: "Male"},
    {state: "NY"},
    {gender: "Female"},
    {gender: "Female"},
    {year: "1990"}
]

如何仅获取唯一的对象?

所需的输出是仅包含唯一对象的数组:

arr = [
    {state: "FL"},
    {state: "NY"},
    {gender: "Male"},
    {gender: "Female"},
    {year: "1990"}
]

我正在尝试使用reduce进行类似的操作,但是通过这种方式,我需要知道对象键:

arr = arr.reduce((acc, curr) => 
    acc.find(e => e['state'] === curr['state']) ? acc : [...acc, curr], [])

这不是重复的,因为其他问题没有使用“动态对象”来获得唯一性

8 个答案:

答案 0 :(得分:6)

您可以对所有对象进行字符串化处理,获取唯一的JSON,然后将字符串转换回对象。

var array = [{ state: "FL" }, { state: "NY" }, { state: "FL" }, { gender: "Male" }, { state: "NY" }, { gender: "Female" }, { gender: "Female" }, { year: "1990" }],
    unique = Array.from(
        new Set(array.map(o => JSON.stringify(o))),
        s => JSON.parse(s)
    );
    
console.log(unique);
.as-console-wrapper { max-height: 100% !important; top: 0; }

如果对象中有多个键,并且因为如果对象中的键的顺序不同,则建议您首先获取条目,对数组进行排序,将其字符串化为一组,然后获取新对象回来。

var array = [{ foo: 42, state: "FL" }, { state: "FL", foo: 42 }, { state: "FL" }, { state: "NY" }, { state: "FL" }, { gender: "Male" }, { state: "NY" }, { gender: "Female" }, { gender: "Female" }, { year: "1990" }],
    unique = Array.from(
        new Set(array.map(o => JSON.stringify(Object.entries(o).sort(([a], [b]) => a.localeCompare(b))))),
        s => Object.assign({}, ...JSON.parse(s).map(([k, v]) => ({ [k]: v })))
    );
    
console.log(unique);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:3)

您可以reduce到一个对象,其中对象中的每个值都是该键中的一个键(因为对象不能在键上加倍,因此可以获取唯一的值),然后将其与Object.values来获取缩小对象中的值,如下所示:

const arr = [{state: "FL"},{state: "NY"},{state: "FL"},{gender: "Male"},{state: "NY"},{gender: "Female"},{gender: "Female"},{year: "1990"}],
reducedObj = arr.reduce((acc, obj) => {
  const [key, val] = Object.entries(obj)[0];
  acc[val] = {[key]: val};
  return acc;
}, {});

res = Object.values(reducedObj);
console.log(res);

答案 2 :(得分:2)

鉴于给定对象的简单性,

想到的快速方法

  1. 使用JSON.stringify将所有对象转换为字符串
  2. 通过将该字符串数组转换为set
  3. 来获取所有唯一值
  4. 再次将字符串转换为对象

var arr = [{state: "FL"},{state: "NY"},{state: "FL"},{gender: "Male"},{state: "NY"},{gender: "Female"},   {gender: "Female"},{year: "1990"}
]

const stringArr = arr.map(str => JSON.stringify(str));
const uniqueStrs = [ ...new Set(stringArr)] // removes duplicates
const result = uniqueStrs.map(str => JSON.parse(str));

console.log(result);

答案 3 :(得分:1)

我也知道,我也知道...但是我的回答更加简洁。

[...new Set(arr.map(JSON.stringify))].map(JSON.parse);

使用JSON.stringify通常会有一些警告,即根据规范,您不能依赖键的顺序来保持一致。如果只有一个键,这将永远不会成为问题。如果每个对象都是通过按相同的顺序添加键来构造的,那么这也不会有问题,因为大多数实现会保留键添加的顺序。

答案 4 :(得分:1)

此性能将比使用JSON.parse和stringify的任何方法都要好。

var arr = [
    {state: "FL"},
    {state: "NY"},
    {state: "FL"},
    {gender: "Male"},
    {state: "NY"},
    {gender: "Female"},
    {gender: "Female"},
    {year: "1990"}
];

const unique = arr => arr.filter((item, index) => !arr.some((i, idx) => idx > index && Object.getOwnPropertyNames(item).every(property => i[property] === item[property])));

console.log(unique(arr));

或使用reduce而不是您尝试过的过滤器

var arr = [
    {state: "FL"},
    {state: "NY"},
    {state: "FL"},
    {gender: "Male"},
    {state: "NY"},
    {gender: "Female"},
    {gender: "Female"},
    {year: "1990"}
];

const unique = arr => arr.reduce((results, item) => {
  if (!results.some(i => Object.getOwnPropertyNames(item).every(property => i[property] === item[property]))) {
    results.push(item);
  }
  return results;
}, []);

console.log(unique(arr));

答案 5 :(得分:0)

这应该有效

const arr = [
  { state: 'FL' },
  { state: 'NY' },
  { state: 'FL' },
  { gender: 'Male' },
  { state: 'NY' },
  { gender: 'Female' },
  { gender: 'Female' },
  { year: '1990' },
];

arr.reduce((array, obj) => {
  for (const target of array) {
    if (JSON.stringify(target) === JSON.stringify(obj)) {
      return array;
    }
    return [...array, obj];
  }
}, []);

答案 6 :(得分:0)

很多方法可以做到这一点:这是两种:

  1. reduce
  2. for loop

var arr = [
    {state: "FL"},
    {state: "NY"},
    {state: "FL"},
    {gender: "Male"},
    {state: "NY"},
    {gender: "Female"},
    {gender: "Female"},
    {year: "1990"}
]

//two solutions
//1. reduce and some
let arr1 = arr.reduce( (acc, currentValue) => {
    const key = Object.keys(currentValue)[0]; //we only have one property!
    const inArr = acc.some((element) => {return element[key] == currentValue[key]});
    if (!inArr)
    {
      acc.push(currentValue);
    }
    return acc;

  },[]);

console.log(arr1);

//2. for loop
//you can still do a for loop (Quick):
const shadow = [];
const iMax= arr.length;
for (let i = 0; i < iMax; i++)
{
   const key = Object.keys(arr[i])[0]; //we only have one property!
  //check if value is not in shadow array
  if (shadow.indexOf(arr[i][key]) == -1)
  {
    arr.push(arr[i]);
    shadow.push(arr[i][key]);
  }
}
//splice off the original values
arr.splice(0, iMax);
console.log(arr);

答案 7 :(得分:0)

使用filter方法:

var arr = [ 
  {state: "FL"}, {state: "NY"}, {state: "FL"}, {gender: "Male"},
  {state: "NY"}, {gender: "Female"}, {gender: "Female"}, {year: "1990"}
]

var len = arr.length ;
var result = [] ;

var result = arr.filter( (cur, inx) => {
  var same = 0 ;
  var curKey = Object.keys(cur)[0] ;
  for ( var i = inx + 1; i < len; i++ ) 
    if ( cur[curKey] === arr[i][curKey] ) { same++; break; }
  return !same;
})

console.log( result ) ;