从对象数组获取唯一对象

时间:2019-04-04 19:29:27

标签: javascript arrays object

我有一个看起来像这样的对象数组:

[
  {
    "places": "NEW YORK",
    "locations": "USA"
  },
  {
    "places": "MONTREAL",
    "locations": "QUEBEC",
    "country": "Canada"
  },
  {
    "places": "MONTREAL",
    "locations": "QUEBEC",
    "country": "Canada"
  }
]

我想过滤并仅获取唯一的条目。我尝试了以下功能,但不起作用:

function onlyUnique(value, index, self) { 
  return self.indexOf(value) === index;
}

使用Set似乎也不起作用。有什么想法吗?

6 个答案:

答案 0 :(得分:2)

使用new Set()的简单解决方案。

const data = [
            {
                "places": "NEW YORK",
                "locations": "USA"
            },
            {
                "places": "MONTREAL",
                "locations": "QUEBEC",
                "country": "Canada"
            },
  {
                "places": "MONTREAL",
                "locations": "QUEBEC",
                "country": "Canada"
            },

        ];
        
const uniqueArray = a => [...new Set(a.map(o => JSON.stringify(o)))].map(s => JSON.parse(s));

console.log(uniqueArray(data)); 

答案 1 :(得分:0)

您可以这样做

let data = data.filter(function (a) {
    let key = a.places + '|' + a.country;
    if (!this[key]) {
        this[key] = true;
        return true;
    }
}, Object.create(null));

console.log(data);

答案 2 :(得分:0)

如果您使用下划线,则可以这样:

var list = [
  {
    "places": "NEW YORK",
    "locations": "USA"
  },
  {
    "places": "MONTREAL",
    "locations": "QUEBEC",
    "country": "Canada"
  },
  {
    "places": "MONTREAL",
    "locations": "QUEBEC",
    "country": "Canada"
  },

];

var uniqList = _.uniq(list, function (item) {
	return item.places+'_'+item.locations+'_'+item.country;
});

console.log(uniqList);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>

答案 3 :(得分:0)

解决方案:

您可以将filter与本地Set对象一起使用。通过比较试图加到size前后的字符串化对象和Set属性,可以通过询问两个数字是否相等来返回唯一数组。


代码:

place_array.filter(v => b.size != b.add(JSON.stringify(v)).size, b = new Set());

为什么使用此代码?

与许多其他答案不同,它依赖于使用过滤器迭代器对数组的单次传递。这意味着它比遍历一个数组的多次循环性能更高。它还仅使用局部变量,这意味着它们不是全局混乱的对象,并且由于filter方法具有功能,因此绝对没有副作用。

注意: 在任何情况下使用Set对象时,性能总是会受到影响。这归结于浏览器内部,但是在发现将stringify转换为Set方法的唯一对象/数组可能是最好的解决方案。尽管数据集非常少,但您可能会发现使用数组或构建自己的特定于任务的对象很实用。

工作示例:

let place_array = [{
    "places": "NEW YORK",
    "locations": "USA"
  },
  {
    "places": "MONTREAL",
    "locations": "QUEBEC",
    "country": "Canada"
  },
  {
    "places": "MONTREAL",
    "locations": "QUEBEC",
    "country": "Canada"
  },

];

let result = place_array.filter(v => b.size != b.add(JSON.stringify(v)).size, b = new Set());

console.log(result);



替代解决方案:

您可以将filter与本地Array对象一起使用。通过确定字符串对象是否已经在数组中并推送是否存在,可以通过询问字符串对象是否不包含在数组中来返回唯一数组。

代码:

place_array.filter(v => !b.includes(s(v)) && !!b.push(s(v)), s = JSON.stringify, b = []);

为什么使用此代码?

尽管Set对象可能有效,但是由于后端处理的原因,它最终比使用Array对象要慢。您可以通过运行类似jsperf的测试来轻松证明这一点:https://jsperf.com/set-vs-ray-includes-battle/1

测试结果:

Test Results Proving Array is Faster than Set

工作示例:

let place_array = [{
    "places": "NEW YORK",
    "locations": "USA"
  },
  {
    "places": "MONTREAL",
    "locations": "QUEBEC",
    "country": "Canada"
  },
  {
    "places": "MONTREAL",
    "locations": "QUEBEC",
    "country": "Canada"
  },

];

let result = place_array.filter(v => !b.includes(s(v)) && !!b.push(s(v)), s = JSON.stringify, b = []);

console.log(result);

答案 4 :(得分:0)

类似这样的东西:

 var distObj = {};
 for(let i = 0; i < obj.places.lenght; i++){
    let tmp = obj.places;
    distObj[i].places = obj[i].places.filter(item => item !== tmp);
 }

如果将其与for(Obj中的k)和回调结合使用,则可以遍历Object中的每个深层和attr

答案 5 :(得分:0)

如果键值像示例中那样简单,则可以执行以下操作来处理实例,其中数组中的对象具有相同的键和值,但顺序不同(自object property order is not guaranteed across browsers起)

  • 使用Object.entries将对象转换为数组,使用JSON.stringify排序并转换为字符串
  • 使用Set删除重复项,并使用JSON.parse将字符串转换回数组,然后使用reduce将字符串转换回对象,以将数组对转换为对象键值对

const arr = [{
    "places": "NEW YORK",
    "locations": "USA"
  },
  {
    "places": "MONTREAL",
    "locations": "QUEBEC",
    "country": "Canada"
  },
  {
    "country": "Canada",
    "places": "MONTREAL",
    "locations": "QUEBEC"
  }
];

let strings = arr.map(obj => JSON.stringify(Object.entries(obj).sort()));

let result = [...new Set(strings)].map((s) => {
  return JSON.parse(s).reduce((acc, [k, v]) => {
    acc[k] = v;
    return acc;
  }, {});
});

console.log(result);
// [{"locations":"USA","places":"NEW YORK"},{"country":"Canada","locations":"QUEBEC","places":"MONTREAL"}]