通过属性创建唯一对象数组

问题描述 投票:0回答:18

我创建了一个对象数组,如下所示:

[
    {
        "lat": 12.123,
        "lng": 13.213,
        "city": "New York"
    },
    {
        "lat": 3.123,
        "lng": 2.213,
        "city": "New York"
    },
    {
        "lat": 1.513,
        "lng": 1.113,
        "city": "London"
    }
]

我正在尝试创建一个新数组,将

places
过滤为仅包含不具有相同
city
属性的对象(纬度/经度重复是可以的)。是否有内置的 JS 或 Jquery 函数可以实现此目的?

javascript jquery filter
18个回答
70
投票

我可能会在过滤过程中使用标志对象(编辑:我不会了,请参阅关于 ES2015 的答案末尾的注释

Set
,如下所示:

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);
    }
});

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


注意:正如 user2736012 在下面指出的那样,对于名称恰好与

if (flags[entry.city])
上存在的属性(例如
Object.prototype
)相同的城市,我的测试
toString
将成立。在这种情况下可能性很小,但有四种方法可以避免这种可能性:

  • (我通常首选的解决方案)创建没有原型的对象:

    var flags = Object.create(null);
    。这是ES5的一个特性。请注意,对于像 IE8 这样的过时浏览器,不能对此进行填充(当参数值为
    Object.create
    时,null 的单参数版本可以是
     except
    )。

  • 使用

    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;
      });
    

62
投票

最短,但不是最佳性能(请参阅下面的更新)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


12
投票

您可以通过仅包含具有尚未添加到 filter

 的属性值的元素来使用 
Set
(之后应将其添加到 
Set
)。这可以使用逻辑与运算符 (
Set
) 在一行中完成。使用这种数据结构具有次线性查找时间的优点(通常
&&
)。
下面是一个通用函数,用于根据对象数组 (
O(1)
) 中的特定属性 (

prop

) 获取唯一的对象数组。请注意,在重复的情况下,仅保留第一个具有属性值的对象。

arr
演示:

const getUniqueBy = (arr, prop) => { const set = new Set; return arr.filter(o => !set.has(o[prop]) && set.add(o[prop])); };


    

https://lodash.com/docs#uniqBy

6
投票

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

var places = [{ lat: 12.123, lng: 13.213, city: 'New York' }, { lat: 3.123, lng: 2.213, city: 'New York' }, { lat: 3.123, lng: 4.123, city: 'Some City' }]; const getUniqueBy = (arr, prop) => { const set = new Set; return arr.filter(o => !set.has(o[prop]) && set.add(o[prop])); }; console.log(getUniqueBy(places, 'city'));

我对 @IgorL 解决方案进行了一些扩展,但扩展了原型并为其提供了选择器函数而不是属性,以使其更加灵活:

4
投票

用途:


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)

我的建议:

3
投票

使用中:

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');

您可以使用地图,以便具有相同键属性(在您的情况下为“城市”)的条目仅出现一次

3
投票

有关 Map 和数组对象的更多信息

这里


Codepen 上的基本示例

另一种选择:


3
投票

您可以将其粘贴到控制台上以查看其工作情况。 它应该适用于所呈现的场景和其他一些场景。


const uniqueBy = prop => list => { const uniques = {} return list.reduce( (result, item) => { if (uniques[item[prop]]) return result uniques[item[prop]] = item return [...result, item] }, [], ) } const uniqueById = uniqueBy('id') uniqueById([ { id: 1, name: 'one' }, { id: 2, name: 'two' }, { id: 1, name: 'one' }, { id: 3, name: 'three' } ])


3
投票
我们可以使用 JavaScript 
Map

2
投票

例如:

const distinctArrayByCity= [ ...new Map(array.map((item) => [item.city, item])).values(), ];



执行代码片段查看结果。

正如评论中指出的,您可以使用对象作为映射,这将允许您避免重复,然后您可以枚举该对象的属性。


1
投票
http://jsfiddle.net/gPRPQ/1/

var places = [{ 'lat': 12.123, 'lng': 13.213, 'city': "New York"}, { 'lat': 3.123, 'lng': 2.213, 'city': "New York"}, { 'lat': 43.123, 'lng': 12.213, 'city': "London"}]; var cityMap = new Map(); places.forEach(p=> cityMap.set(p.city, p)); console.log([...cityMap.values()]);

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);
}

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); 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; }

0
投票
Javascript

数组列表中删除重复的城市是


places
    

基于上面
https://stackoverflow.com/a/18773857/49564

0
投票

var places = [{ 'lat': 12.123, 'lng': 13.213, 'city': "New York"}, { 'lat': 3.123, 'lng': 2.213, 'city': "New York"}, { 'lat': 43.123, 'lng': 12.213, 'city': "London"}]; var unique = []; var tempArr = []; places.forEach((value, index) => { if (unique.indexOf(value.city) === -1) { unique.push(value.city); } else { tempArr.push(index); } }); tempArr.reverse(); tempArr.forEach(ele => { places.splice(ele, 1); }); console.log(places);

我想你想要这个,

0
投票
注意:

无需图书馆。

export function isDistinct<T>(mapper: (value: T) => string): (value: T) => boolean { const keys: { [index: string]: boolean } = {}; return (entry: T) => { const key = mapper(entry); if (keys[key] !== undefined) { return false; } return keys[key] = true; }; } // Usage example: const items = [ { id: 1 }, { id: 2 }, { id: 3 }, { id: 1 } ]; const unique = items.filter(isDistinct(i => i.id));

rafaelbiten

0
投票

let array = [{ id: 1}, {id: 2}, {id: 3}]; function addUniqeObj(data) { let index = -1; for(let i = 0, i < array.length; i++) { if(array[i].id === data.id) { index = i; } } if(index > -1) { array[index] = data; } else { array.push(data) } }


    

另一种获取唯一对象数组的方法。


0
投票

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


-1
投票

您可以在这里查看小提琴


    

© www.soinside.com 2019 - 2024. All rights reserved.