按属性创建唯一对象数组

我创建了一个像这样的对象数组:

var places = []; var a = {}; a.lat = 12.123; a.lng = 13.213; a.city = "New York"; places.push(a); var b = {}; b.lat = 3.123; b.lng = 2.213; b.city = "New York"; places.push(b); ... 

我正在尝试创建一个新的数组,过滤地点只包含没有相同城市属性的对象(lat / lng重复项是可以的)。 是否有内置的JS或Jquery函数来实现这一目标?

我可能在过滤期间使用了flags对象,如下所示:

 var flags = {}; var newPlaces = places.filter(function(entry) { if (flags[entry.city]) { return false; } flags[entry.city] = true; return true; }); 

它使用来自ECMAScript5(ES5)的Array#filter ,这是可以填充的ES5添加之一(为几个选项搜索“es5 shim”)。

你可以在没有filter情况下做到这一点,当然,它只是更冗长:

 var flags = {}; var newPlaces = []; var index; for (index = 0; index < places.length; ++index) { if (!flags[entry.city]) { flags[entry.city] = true; newPlaces.push(entry); } }); 

以上两者都假定应保留给定城市的第一个对象,并丢弃所有其他对象。


注意:正如user2736012指出的那样,对于名称恰好与Object.prototype上存在的属性(如toString相同的城市,我的测试if (flags[entry.city])将为true。 在这种情况下非常不可能,但有四种方法可以避免这种可能性:

  • (我通常喜欢的解决方案)创建没有原型的对象: var flags = Object.create(null); 。 这是ES5的一个function。 请注意,对于像IE8这样的过时浏览器,不能对此进行填充( Object.create的单参数版本可以是该参数的值为null除外 )。

  • 使用hasOwnProperty进行测试,例如if (flags.hasOwnProperty(entry.city))

  • 在您知道对于任何Object.prototype属性不存在的前缀上添加前缀,例如xx

     var key = "xx" + entry.city; if (flags[key]) { // ... } flags[key] = true; 
  • 从ES2015开始,您可以使用Set代替:

     const flags = new Set(); const newPlaces = places.filter(entry => { if (flags.has(entry.city)) { return false; } flags.add(entry.city); return true; }); 

es6的最短但不是最佳性能 (参见下面的更新)解决方案:

 function unique(array, propertyName) { return array.filter((e, i) => array.findIndex(a => a[propertyName] === e[propertyName]) === i); } 

性能: https : //jsperf.com/compare-unique-array-by-property

我的建议 :

 Array.prototype.uniqueCity = function() { var processed = []; for (var i=this.length-1; i>=0; i--){ if (processed.indexOf(this[i].city)<0) { processed.push(this[i].city); } else { this.splice(i, 1); } } } 

正在使用 :

 places.uniqueCity(); 

要么

 Array.prototype.uniqueObjectArray = function(field) { var processed = []; for (var i=this.length-1; i>=0; i--) { if (this[i].hasOwnProperty(field)) { if (processed.indexOf(this[i][field])<0) { processed.push(this[i][field]); } else { this.splice(i, 1); } } } } places.uniqueObjectArray('city'); 

通过上述操作,您可以按对象中的任何字段对数组进行排序, 即使某些对象不存在这些字段。

要么

 function uniqueCity(array) { var processed = []; for (var i=array.length-1; i>=0; i--){ if (processed.indexOf(array[i].city)<0) { processed.push(array[i].city); } else { array.splice(i, 1); } } return array; } places = uniqueCity(places); 

我在@IgorL解决方案上进行了一些扩展,但扩展了原型并给它一个选择器函数而不是属性使它更灵活:

 Array.prototype.unique = function(selector) { return this.filter((e, i) => this.findIndex((a) => { if (selector) { return selector(a) === selector(e); } return a === e; }) === i); }; 

用法:

 // with no param it uses strict equals (===) against the object let primArr = ['one','one','two','three','one'] primArr.unique() // ['one','two','three'] let a = {foo:123} let b = {foo:123} let fooArr = [a,a,b] fooArr.unique() //[a,b] // alternatively, you can pass a selector function fooArr.unique(item=>item.foo) //[{foo:123}] (first "unique" item returned) 

绝对不是最高效的方法,但只要选择器很简单且数组不是很大,它应该可以正常工作。

在打字稿中

 Array.prototype.unique = function(this: T[], selector?: (item: T) => object): T[] { return this.filter((e, i) => this.findIndex((a) => { if (selector) { return selector(a) === selector(e); } return a === e; }) === i); }; 

正如评论中指出的那样,您可以将对象用作地图,这样可以避免重复,然后您可以枚举对象的属性。

工作小提琴: http : //jsfiddle.net/gPRPQ/1/

 var places = []; var a = {}; a.lat = 12.123; a.lng = 13.213; a.city = "New York"; places.push(a); var b = {}; b.lat = 3.123; b.lng = 2.213; b.city = "New York"; places.push(b); var unique = {} for (var i = 0; i < places.length; i++) { var place = places[i]; unique[place.city] = place; } for (var name in unique) { var place = unique[name]; console.log(place); } 

https://lodash.com/docs#uniqBy

https://github.com/lodash/lodash/blob/4.13.1/lodash.js#L7711

 /** * This method is like `_.uniq` except that it accepts `iteratee` which is * invoked for each element in `array` to generate the criterion by which * uniqueness is computed. The iteratee is invoked with one argument: (value). * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The array to inspect. * @param {Array|Function|Object|string} [iteratee=_.identity] * The iteratee invoked per element. * @returns {Array} Returns the new duplicate free array. * @example * * _.uniqBy([2.1, 1.2, 2.3], Math.floor); * // => [2.1, 1.2] * * // The `_.property` iteratee shorthand. * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 1 }, { 'x': 2 }] */ 
 var places = []; var a = {}; a.lat = 12.123; a.lng = 13.213; a.city = "New York"; places.push(a); var b = {}; b.lat = 3.123; b.lng = 2.213; b.city = "New York"; places.push(b); getUniqAR(places,'city'); //Return Uniq Array by property function getUniqAR(Data,filter){ var uniar =[]; Data.forEach(function(item,ind,arr){ var dupi=false; if(!uniar.length) uniar.push(item) //push first obj into uniq array uniar.forEach(function(item2, ind2,arr){ if(item2[filter] == item[filter]){ //check each obj prop of uniq array dupi=true; //if values are same put duplicate is true } }) if(!dupi){ uniar.push(item)} //if no duplicate insert to uniq }) console.log(uniar) return uniar; } 

您可以使用Map,因此具有相同键属性的条目(在您的情况下为“city”)仅出现一次

 module.exports = (array, prop) => { const keyValueArray = array.map(entry => [entry[prop], entry]); const map = new Map(keyValueArray); return Array.from(map.values()); }; 

有关Map和array对象的更多信息,请点击此处

Codepen的基本示例

这个post可能很旧,但我认为我应该分享它。 它基于Pure JavaScript,并根据指定的属性删除重复对象。

 function removeDuplicates(originalArray, properties) { var newArray = []; var index = 0; var lookupObject = {}; var totalProperties = properties.length; for (var i = 0; i < originalArray.length; i++) { var exists = false; for (var a = 0; a < newArray.length; a++) { var propsFound = 0; for (var b = 0; b < totalProperties; b++) { if (originalArray[i][properties[b]] == newArray[a][properties[b]]) { propsFound++; } } //If there is a match then break the for loop if (propsFound == totalProperties) { exists = true; break; } } //End of New Array if (!exists) { newArray[index] = originalArray[i]; index++; } } //End of originalArray return newArray; } 

你可以在这里查看小提琴