从JavaScript中的对象数组中删除重复项


373

我有一个包含对象数组的对象。

things = new Object();

things.thing = new Array();

things.thing.push({place:"here",name:"stuff"});
things.thing.push({place:"there",name:"morestuff"});
things.thing.push({place:"there",name:"morestuff"});

我想知道什么是从数组中删除重复对象的最佳方法。举例来说,事物……东西将变成……

{place:"here",name:"stuff"},
{place:"there",name:"morestuff"}

您是说如何停止将所有相同参数添加到数组的哈希表/对象?
马修·洛克

1
Mathew->如果更简单的方法是首先防止将重复的对象添加到数组中,而不是稍后将其过滤掉,是的,这也很好。
特拉维斯

2
人们如何命名变量,这让我感到惊讶。有时我认为他们真的想使它不必要地复杂。接下来看到的将是aaaaa.aaaa.push(...):)
dazito

Answers:


154

一种原始方法是:

var obj = {};

for ( var i=0, len=things.thing.length; i < len; i++ )
    obj[things.thing[i]['place']] = things.thing[i];

things.thing = new Array();
for ( var key in obj )
    things.thing.push(obj[key]);

15
您永远不要在for循环中使用该长度,因为它会减慢每次迭代时计算它的速度。将其分配给循环外的变量,然后传递该变量而不是Things.thing.length。
0v3rth3d4wn 2014年

12
@aefxx我不太了解此功能,如何处理“位置”相同但名称不同的情况,应该考虑还是不考虑dup?
2015年

2
尽管这可行,但它不会处理排序数组,因为从不保证顺序获取键。因此,您最终再次对其进行了排序。现在,假设数组未排序,但是其顺序很重要,则无法确保顺序保持不变
Deepak GM

1
@DeepakGM你是绝对正确的。答案将不会(必须)保留给定的顺序。如果这是一项要求,则应寻找另一种解决方案。
aefxx

如何修改上面的内容以从包含X以及重复数据删除的数组中删除对象?
Ryan Holton

435

es6魔法怎么样?

things.thing = things.thing.filter((thing, index, self) =>
  index === self.findIndex((t) => (
    t.place === thing.place && t.name === thing.name
  ))
)

参考网址

更通用的解决方案是:

const uniqueArray = things.thing.filter((thing, index) => {
  const _thing = JSON.stringify(thing);
  return index === things.thing.findIndex(obj => {
    return JSON.stringify(obj) === _thing;
  });
});

Stackblitz示例


81
可以缩短为:things.thing = things.thing.filter((thing, index, self) => self.findIndex(t => t.place === thing.place && t.name === thing.name) === index)
乔什·科尔

完美的作品!var uniqueArrayOfObjects = arrayOfObjects.filter(function(obj,index,self){return index === self.findIndex(function(t){return t ['obj-property'] === obj ['obj-property'] });}); 确保使用正确的JS语法。
Mohamed Salem Lamiri

这些是正确的JS语法。您没有使用1)粗箭头功能2)隐式返回或3)点表示法。您使用的是ES5语法。其他大多数是ES6(ECMA2015)。所有内容均在2017年有效。请参见jaredwilli的评论。
agm1984

8
@vsync只是将@BKM的答案汇总起来,一个通用的解决方案是:const uniqueArray = arrayOfObjects.filter((object,index) => index === arrayOfObjects.findIndex(obj => JSON.stringify(obj) === JSON.stringify(object))); jsfiddle.net/x9ku0p7L/28
Eydrian

9
这里的关键是findIndex()方法返回第一个元素的索引,因此,如果有第二个元素匹配,则将永远不会在过滤器中找到并添加它。我盯着它
看了

111

如果可以使用下划线或lodash之类的Javascript库,建议您查看_.uniq其库中的函数。来自lodash

_.uniq(array, [isSorted=false], [callback=_.identity], [thisArg])

基本上,您传入的数组是此处的对象文字,然后传入要删除原始数据数组中重复项的属性,如下所示:

var data = [{'name': 'Amir', 'surname': 'Rahnama'}, {'name': 'Amir', 'surname': 'Stevens'}];
var non_duplidated_data = _.uniq(data, 'name'); 

更新:Lodash现在也引入了一个.uniqBy


3
@Praveen Pds:我在代码示例中是否说过有关下划线的内容?我说过“ lodash”具有此功能,而下划线也具有类似的功能。在投反对票之前,请仔细阅读答案。
ambodi 2015年

//使用_underscore.js列出唯一的对象holdingObject = _.uniq(holdingObject,function(item,key,name){return item.name;});
praveenpds

26
注意:您现在需要使用uniqBy代替uniq,例如_.uniqBy(data, 'name')...文档:lodash.com/docs#uniqBy
drmrbrewer

82

我有完全相同的要求,即根据单个字段上的重复项删除数组中的重复对象。我在这里找到了代码:Javascript:从对象数组中删除重复项

因此,在我的示例中,我要从数组中删除具有重复的licenseNum字符串值的任何对象。

var arrayWithDuplicates = [
    {"type":"LICENSE", "licenseNum": "12345", state:"NV"},
    {"type":"LICENSE", "licenseNum": "A7846", state:"CA"},
    {"type":"LICENSE", "licenseNum": "12345", state:"OR"},
    {"type":"LICENSE", "licenseNum": "10849", state:"CA"},
    {"type":"LICENSE", "licenseNum": "B7037", state:"WA"},
    {"type":"LICENSE", "licenseNum": "12345", state:"NM"}
];

function removeDuplicates(originalArray, prop) {
     var newArray = [];
     var lookupObject  = {};

     for(var i in originalArray) {
        lookupObject[originalArray[i][prop]] = originalArray[i];
     }

     for(i in lookupObject) {
         newArray.push(lookupObject[i]);
     }
      return newArray;
 }

var uniqueArray = removeDuplicates(arrayWithDuplicates, "licenseNum");
console.log("uniqueArray is: " + JSON.stringify(uniqueArray));

结果:

uniqueArray是:

[{"type":"LICENSE","licenseNum":"10849","state":"CA"},
{"type":"LICENSE","licenseNum":"12345","state":"NM"},
{"type":"LICENSE","licenseNum":"A7846","state":"CA"},
{"type":"LICENSE","licenseNum":"B7037","state":"WA"}]

1
如果该函数也可以过滤“虚假”对象,则这将更为有用。for(var i in array) { if(array[i][prop]){ //valid lookupObject[array[i][prop]] = array[i]; } else { console.log('falsy object'); } }
阿卜杜勒·萨迪克·雅尔辛

为什么不使用以下方法降低复杂度0(n): for (let i in originalArray) { if (lookupObject[originalArray[i]['id']] === undefined) { newArray.push(originalArray[i]); } lookupObject[originalArray[i]['id']] = originalArray[i]; }
Tudor

这是最好的方法,因为了解不希望被复制的内容很重要。现在可以通过针对E6标准的reducer来完成此操作吗?
基督教马修

69

适用于ES6 +的最短衬管

id在数组中查找唯一的。

arr.filter((v,i,a)=>a.findIndex(t=>(t.id === v.id))===i)

通过多个属性(placename)唯一

arr.filter((v,i,a)=>a.findIndex(t=>(t.place === v.place && t.name===v.name))===i)

所有属性唯一(对于大型阵列,这将很慢)

arr.filter((v,i,a)=>a.findIndex(t=>(JSON.stringify(t) === JSON.stringify(v)))===i)

保留最后一次出现。

arr.slice().reverse().filter((v,i,a)=>a.findIndex(t=>(t.id === v.id))===i).reverse()

2
魔术,这是真正的答案
Luis Contreras

48

使用一套的班轮

var things = new Object();

things.thing = new Array();

things.thing.push({place:"here",name:"stuff"});
things.thing.push({place:"there",name:"morestuff"});
things.thing.push({place:"there",name:"morestuff"});

// assign things.thing to myData for brevity
var myData = things.thing;

things.thing = Array.from(new Set(myData.map(JSON.stringify))).map(JSON.parse);

console.log(things.thing)

说明:

  1. new Set(myData.map(JSON.stringify))使用字符串化myData元素创建Set对象。
  2. 设置对象将确保每个元素都是唯一的。
  3. 然后,我使用Array.from根据创建的集合的元素创建一个数组。
  4. 最后,我使用JSON.parse将字符串化的元素转换回对象。

18
问题是{a:1,b:2}将不等于{b:2,a:1}
PirateApp '17

2
请记住,日期属性会出现问题
MarkosyanArtur

该行使用原始对象数组中不存在的行对象创建随机空值。你能帮忙吗?
B1K

46

在一行中使用ES6 +,您可以通过按键获得唯一的对象列表:

const unique = [...new Map(arr.map(item => [item[key], item])).values()]

可以放入一个函数中:

function getUniqueListBy(arr, key) {
    return [...new Map(arr.map(item => [item[key], item])).values()]
}

这是一个工作示例:

const arr = [
    {place: "here",  name: "x", other: "other stuff1" },
    {place: "there", name: "x", other: "other stuff2" },
    {place: "here",  name: "y", other: "other stuff4" },
    {place: "here",  name: "z", other: "other stuff5" }
]

function getUniqueListBy(arr, key) {
    return [...new Map(arr.map(item => [item[key], item])).values()]
}

const arr1 = getUniqueListBy(arr, 'place')

console.log("Unique by place")
console.log(JSON.stringify(arr1))

console.log("\nUnique by name")
const arr2 = getUniqueListBy(arr, 'name')

console.log(JSON.stringify(arr2))

它是如何工作的

首先,以可以用作Map输入的方式重新映射数组

arr.map(item => [item [key],item]);

这意味着该数组的每一项将转换为具有2个元素的另一个数组;所述选择的键作为第一元件和整个初始项目作为第二元件,这被称为一个条目(例如,阵列的条目映射条目)。而这里是官方的文档与演示如何在地图构造函数到数组项的例子。

放置钥匙的示例:

[["here", {place: "here",  name: "x", other: "other stuff1" }], ...]

其次,我们将此修改后的数组传递给Map构造函数,这就是神奇的事情。映射将消除重复的键值,仅保留同一键的最后插入值。 注意:Map保持插入顺序。(检查地图和对象之间的差异

新地图(上面刚刚映射的条目数组)

第三,我们使用地图值检索原始项目,但是这次没有重复项。

新Map(mappedArr).values()

最后一个是将这些值添加到一个新的新数组中,以便它看起来像是初始结构并返回:

返回[... new Map(mappedArr).values()]


这无法回答原始问题,因为这是在搜索id。这个问题需要整个对象在所有领域中都是唯一的,例如placeandname
L. Holanda

您的ES6函数看起来非常简洁实用。您能再解释一下吗?到底是怎么回事?是否删除了第一个或最后一个重复项?还是随机的,哪些重复项会被删除?那样会很有帮助,谢谢。
David Schumann

据我所知,将创建一个以属性值为键的Map。但是,如何或是否保留数组的顺序并不是100%。
David Schumann

1
@DavidSchumann,您好,我将更新答案并解释其工作原理。但是为了简短回答,保留了该顺序,并删除了第一个顺序...考虑一下如何将其插入到地图中...它会检查键是否已存在,它将对其进行更新,然后保留最后一个
V Sambor

30

如果只需要按对象的一个​​字段进行比较,则可以使用数组迭代方法执行此操作,这是另一种选择:

    function uniq(a, param){
        return a.filter(function(item, pos, array){
            return array.map(function(mapItem){ return mapItem[param]; }).indexOf(item[param]) === pos;
        })
    }

    uniq(things.thing, 'place');

尽管它的阶数大于O(n²),但是这适合我的用例,因为我的数组大小始终小于30。谢谢!
Sterex

24

一个班轮在这里

let arr = [
  {id:1,name:"sravan ganji"},
  {id:2,name:"anu"},
  {id:4,name:"mammu"},
  {id:3,name:"sanju"},
  {id:3,name:"ram"},
];

console.log(Object.values(arr.reduce((acc,cur)=>Object.assign(acc,{[cur.id]:cur}),{})))


1
如果您只想删除具有单个重复值的对象,而对于完全复制的对象则不是那么干净,那很干净。
大卫·巴克

22

如果您要等到所有添加之后才消除重复项,那么典型的方法是先对数组排序,然后消除重复项。排序避免了在遍历每个元素时使用N * N方法扫描数组中每个元素的方法。

“消除重复项”功能通常称为uniqueuniq。一些现有的实现可以将两个步骤结合起来,例如,原型的uniq

这篇文章有一些想法,尝试(和一些避免:-))如果你的图书馆还没有一个!我个人认为这是最直接的方法:

    function unique(a){
        a.sort();
        for(var i = 1; i < a.length; ){
            if(a[i-1] == a[i]){
                a.splice(i, 1);
            } else {
                i++;
            }
        }
        return a;
    }  

    // Provide your own comparison
    function unique(a, compareFunc){
        a.sort( compareFunc );
        for(var i = 1; i < a.length; ){
            if( compareFunc(a[i-1], a[i]) === 0){
                a.splice(i, 1);
            } else {
                i++;
            }
        }
        return a;
    }

没有自然排序顺序的通用对象将无法使用。
Tim Down'2

没错,我添加了用户提供的比较版本。
maccullt'2

用户提供的比较版本将无法使用,因为如果您的比较函数function(_a,_b){return _a.a===_b.a && _a.b===_b.b;}不对数组进行排序。
graham.reeds 2010年

1
那是无效的比较功能。从developer.mozilla.org/en/Core_JavaScript_1.5_Reference/… ...函数compare(a,b){如果(按某种排序标准,a小于b)则返回-1;如果(按排序标准,a大于b)返回1;// a必须等于b返回0; }
Maccullt 2010年

22

最简单的方法是使用filter

var uniq = {}
var arr  = [{"id":"1"},{"id":"1"},{"id":"2"}]
var arrFiltered = arr.filter(obj => !uniq[obj.id] && (uniq[obj.id] = true));
console.log('arrFiltered', arrFiltered)


6
在Stack Overflow上的优良作法是添加一个说明,说明为什么您的解决方案应该起作用,尤其是您的解决方案比其他答案更好。有关更多信息,请阅读“ 如何回答”
塞缪尔·柳

这无法回答原始问题,因为这是在搜索id。这个问题需要整个对象在所有领域中都是唯一的,例如placeandname
L. Holanda

16

这是执行此操作的通用方法:传递一个函数来测试数组的两个元素是否相等。在这种情况下,它将比较两个比较对象的name和的值place

ES5答案

function removeDuplicates(arr, equals) {
    var originalArr = arr.slice(0);
    var i, len, val;
    arr.length = 0;

    for (i = 0, len = originalArr.length; i < len; ++i) {
        val = originalArr[i];
        if (!arr.some(function(item) { return equals(item, val); })) {
            arr.push(val);
        }
    }
}

function thingsEqual(thing1, thing2) {
    return thing1.place === thing2.place
        && thing1.name === thing2.name;
}

var things = [
  {place:"here",name:"stuff"},
  {place:"there",name:"morestuff"},
  {place:"there",name:"morestuff"}
];

removeDuplicates(things, thingsEqual);
console.log(things);

ES3原始答案

function arrayContains(arr, val, equals) {
    var i = arr.length;
    while (i--) {
        if ( equals(arr[i], val) ) {
            return true;
        }
    }
    return false;
}

function removeDuplicates(arr, equals) {
    var originalArr = arr.slice(0);
    var i, len, j, val;
    arr.length = 0;

    for (i = 0, len = originalArr.length; i < len; ++i) {
        val = originalArr[i];
        if (!arrayContains(arr, val, equals)) {
            arr.push(val);
        }
    }
}

function thingsEqual(thing1, thing2) {
    return thing1.place === thing2.place
        && thing1.name === thing2.name;
}

removeDuplicates(things.thing, thingsEqual);

1
即使两个对象共享相同的属性和值,它们的求值也不相等。
肯纳贝克

是的我知道。但是,公平地说,我没有正确阅读问题:我没有发现它是具有相同属性的对象,他需要清除掉这些属性。我将编辑我的答案。
Tim Down'2

1
而不是在arrayContains内部使用-使用Array.prototype..some方法如果数组成员之一匹配条件,则返回true
MarkosyanArtur

13

要再添加一个到列表中。使用ES6并Array.reduceArray.find
在此示例中,根据guid属性过滤对象。

let filtered = array.reduce((accumulator, current) => {
  if (! accumulator.find(({guid}) => guid === current.guid)) {
    accumulator.push(current);
  }
  return accumulator;
}, []);

扩展此属性以允许选择属性并将其压缩为一个衬里:

const uniqify = (array, key) => array.reduce((prev, curr) => prev.find(a => a[key] === curr[key]) ? prev : prev.push(curr) && prev, []);

要使用它,请将对象数组和要删除重复项的键的名称作为字符串值传递:

const result = uniqify(myArrayOfObjects, 'guid')

11

您也可以使用Map

const dedupThings = Array.from(things.thing.reduce((m, t) => m.set(t.place, t), new Map()).values());

完整样本:

const things = new Object();

things.thing = new Array();

things.thing.push({place:"here",name:"stuff"});
things.thing.push({place:"there",name:"morestuff"});
things.thing.push({place:"there",name:"morestuff"});

const dedupThings = Array.from(things.thing.reduce((m, t) => m.set(t.place, t), new Map()).values());

console.log(JSON.stringify(dedupThings, null, 4));

结果:

[
    {
        "place": "here",
        "name": "stuff"
    },
    {
        "place": "there",
        "name": "morestuff"
    }
]

+1,不错,请多解释dedupThing的内部工作原理-好的一面是我现在了解到reduce:D
MimiEAM 17-4-6

11

ang,孩子们,让我们把这东西压碎,为什么不呢?

let uniqIds = {}, source = [{id:'a'},{id:'b'},{id:'c'},{id:'b'},{id:'a'},{id:'d'}];
let filtered = source.filter(obj => !uniqIds[obj.id] && (uniqIds[obj.id] = true));
console.log(filtered);
// EXPECTED: [{id:'a'},{id:'b'},{id:'c'},{id:'d'}];


这无法回答原始问题,因为这是在搜索id。这个问题需要整个对象,在所有的领域,如唯一placename
L. Holanda

这是对问题的上述概括的改进。原来的问题被张贴9年前,所以原来的海报可能不担心placename今天。任何阅读此线程的人都在寻找一种优化方法来简化对象列表,这是一种紧凑的方法。
悬崖厅”

11

TypeScript解决方案

这将删除重复的对象,并保留对象的类型。

function removeDuplicateObjects(array: any[]) {
  return [...new Set(array.map(s => JSON.stringify(s)))]
    .map(s => JSON.parse(s));
}

2
这是伟大的和短暂的!
mojjj

还有超级慢...
L. Holanda

7

考虑中 lodash.uniqWith

var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];

_.uniqWith(objects, _.isEqual);
// => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]

太好了!谢谢;-)
DonFabiolas

1
lodash的uniq或uniqBy都没有做到这一点,但是您的解决方案做到了。谢谢!但是,如果是直接复制,请提供代码源。lodash.com/docs/4.17.10#uniqWith
Manu CJ

5

另一个选择是创建一个自定义indexOf函数,该函数将比较每个对象所选属性的值并将其包装在reduce函数中。

var uniq = redundant_array.reduce(function(a,b){
      function indexOfProperty (a, b){
          for (var i=0;i<a.length;i++){
              if(a[i].property == b.property){
                   return i;
               }
          }
         return -1;
      }

      if (indexOfProperty(a,b) < 0 ) a.push(b);
        return a;
    },[]);

这对我来说非常lodash.isequal有用 -我将它与npm软件包配对,作为轻量级的对象比较器来执行唯一的数组过滤...例如不同的对象数组。只是换入if (_.isEqual(a[i], b)) {而不是寻找@单一财产
SliverNinja-MSFT

5

let myData = [{place:"here",name:"stuff"}, 
 {place:"there",name:"morestuff"},
 {place:"there",name:"morestuff"}];


let q = [...new Map(myData.map(obj => [JSON.stringify(obj), obj])).values()];

console.log(q)

使用ES6和的单线new Map()

// assign things.thing to myData
let myData = things.thing;

[...new Map(myData.map(obj => [JSON.stringify(obj), obj])).values()];

细节:-

  1. 这样做.map()的数据列表和每个单独的对象转换为[key, value]一对阵列(长度= 2),所述第一元件(键)将是stringified物体和第二(值)的版本将是一个object本身。
  2. 将上面创建的数组列表添加到 new Map()会将键作为stringified对象,并且添加任何相同的键都将导致覆盖已经存在的键。
  3. 使用 .values()将为MapIterator提供Map中的所有值(obj在我们的示例中)
  4. 最后,spread ...操作员使用上述步骤中的值为新数组赋值。

4

这是es6的解决方案,您只想保留最后一项。该解决方案功能齐全且符合Airbnb风格。

const things = {
  thing: [
    { place: 'here', name: 'stuff' },
    { place: 'there', name: 'morestuff1' },
    { place: 'there', name: 'morestuff2' }, 
  ],
};

const removeDuplicates = (array, key) => {
  return array.reduce((arr, item) => {
    const removed = arr.filter(i => i[key] !== item[key]);
    return [...removed, item];
  }, []);
};

console.log(removeDuplicates(things.thing, 'place'));
// > [{ place: 'here', name: 'stuff' }, { place: 'there', name: 'morestuff2' }]

您可以删除重复项,也可以使用此代码删除所有重复项。尼斯
sg28,19年

4

removeDuplicates()接收一个对象数组,并返回一个没有任何重复对象的新数组(基于id属性)。

const allTests = [
  {name: 'Test1', id: '1'}, 
  {name: 'Test3', id: '3'},
  {name: 'Test2', id: '2'},
  {name: 'Test2', id: '2'},
  {name: 'Test3', id: '3'}
];

function removeDuplicates(array) {
  let uniq = {};
  return array.filter(obj => !uniq[obj.id] && (uniq[obj.id] = true))
}

removeDuplicates(allTests);

预期结果:

[
  {name: 'Test1', id: '1'}, 
  {name: 'Test3', id: '3'},
  {name: 'Test2', id: '2'}
];

首先,我们将变量uniq的值设置为一个空对象。

接下来,我们筛选对象数组。筛选器会创建一个新数组,其中包含所有通过提供的功能实现的测试的元素。

return array.filter(obj => !uniq[obj.id] && (uniq[obj.id] = true));

上面,我们使用&&的短路功能。如果&&的左侧求值为true,则返回&&右侧的值。如果左侧为假,则返回&&左侧的内容。

对于每个object(obj),我们都会在uniq中检查名为obj.id的值的属性(在这种情况下,在第一次迭代中它将检查属性'1'。)我们想要返回的结果与之相反(或者为true或false),这就是我们使用!的原因 在!uniq [obj.id]中。如果uniq已经具有id属性,则返回true,结果为false(!),告诉过滤器函数不要添加该obj。但是,如果找不到obj.id属性,它将返回false,然后求值为true(!),并返回&&右侧的所有内容,或者返回(uniq [obj.id] = true)。这是一个真实值,它告诉filter方法将该obj添加到返回的数组中,并且还将属性{1:true}添加到uniq中。这样可以确保不会再添加任何其他具有相同ID的obj实例。


也许解释一下您的代码,它如何回答问题?
mix3d

谢谢,mix3d。我增加了澄清。
MarkN

感谢您的解释!此解决方案对我有用,并且与此处发布的其他几个解决方案相似,尽管我不知道发生了什么:)
Tim Molloy

3
let data = [
  {
    'name': 'Amir',
    'surname': 'Rahnama'
  }, 
  {
    'name': 'Amir',
    'surname': 'Stevens'
  }
];
let non_duplicated_data = _.uniqBy(data, 'name');

9
请围绕您的代码添加说明,以便将来的访问者可以了解您在做什么。谢谢。
错误

您的答案取决于外部代码库...
Taylor A. Leach

3

我相信reduce完美结合JSON.stringify来比较对象并有选择地添加那些不在累加器中的对象的组合是一种优雅的方法。

请记住,JSON.stringify在极端情况下,如果阵列中有许多对象并且它们很复杂(大多数情况下都是BUT),这可能会成为性能问题,这是恕我直言的最短方法。

var collection= [{a:1},{a:2},{a:1},{a:3}]

var filtered = collection.reduce((filtered, item) => {
  if( !filtered.some(filteredItem => JSON.stringify(filteredItem) == JSON.stringify(item)) )
    filtered.push(item)
  return filtered
}, [])

console.log(filtered)

编写相同内容(但效率较低)的另一种方法:

collection.reduce((filtered, item) => 
  filtered.some(filteredItem => 
    JSON.stringify(filteredItem ) == JSON.stringify(item)) 
      ? filtered
      : [...filtered, item]
, [])

最适合我的那个!谢谢!
javascript110899,

2

继续探索从对象数组中删除重复项的ES6方法:将thisArg参数设置为Array.prototype.filterto new Set提供了不错的选择:

const things = [
  {place:"here",name:"stuff"},
  {place:"there",name:"morestuff"},
  {place:"there",name:"morestuff"}
];

const filtered = things.filter(function({place, name}) {

  const key =`${place}${name}`;

  return !this.has(key) && this.add(key);

}, new Set);

console.log(filtered);

但是,它不适用于箭头函数() =>,因为箭头函数this已绑定到其词法范围。


2

一行中的es6魔法...可读性强!

// returns the union of two arrays where duplicate objects with the same 'prop' are removed
const removeDuplicatesWith = (a, b, prop) => a.filter(x => !b.find(y => x[prop] === y[prop]);

2

使用ES6“减少”和“查找”阵列辅助方法的简单解决方案

有效且完美地工作!

"use strict";

var things = new Object();
things.thing = new Array();
things.thing.push({
    place: "here",
    name: "stuff"
});
things.thing.push({
    place: "there",
    name: "morestuff"
});
things.thing.push({
    place: "there",
    name: "morestuff"
});

// the logic is here

function removeDup(something) {
    return something.thing.reduce(function (prev, ele) {
        var found = prev.find(function (fele) {
            return ele.place === fele.place && ele.name === fele.name;
        });
        if (!found) {
            prev.push(ele);
        }
        return prev;
    }, []);
}
console.log(removeDup(things));

这对我帮助很大,谢谢
jpisty

1

如果您不介意之后对唯一数组进行排序,那么这将是一个有效的解决方案:

things.thing
  .sort(((a, b) => a.place < b.place)
  .filter((current, index, array) =>
    index === 0 || current.place !== array[index - 1].place)

这样,您只需要比较当前元素和数组中的前一个元素即可。在筛选之前进行一次排序(O(n*log(n)))比在整个数组中为每个数组元素(O(n²))搜索重复项便宜。


1

这是从对象数组中删除重复项的简单方法。

我经常处理数据,这对我很有用。

const data = [{name: 'AAA'}, {name: 'AAA'}, {name: 'BBB'}, {name: 'AAA'}];
function removeDuplicity(datas){
    return datas.filter((item, index,arr)=>{
    const c = arr.map(item=> item.name);
    return  index === c.indexOf(item.name)
  })
}

console.log(removeDuplicity(data))

将打印到控制台:

[[object Object] {
name: "AAA"
}, [object Object] {
name: "BBB"
}]

此解决方案旨在消除静态数组中的重复项,但是当您将数据从后端推送到数据数组中时,请考虑使用replace。因为在这种情况下,将删除推送到数据数组的新值,而“旧”值仍将存储在数据数组中。
Juraj

1
str =[
{"item_id":1},
{"item_id":2},
{"item_id":2}
]

obj =[]
for (x in str){
    if(check(str[x].item_id)){
        obj.push(str[x])
    }   
}
function check(id){
    flag=0
    for (y in obj){
        if(obj[y].item_id === id){
            flag =1
        }
    }
    if(flag ==0) return true
    else return false

}
console.log(obj)

str是一个对象数组。存在具有相同值的对象(在此举一个小例子,有两个对象的item_id与2相同)。check(id)是一种检查是否存在具有相同item_id的对象的函数。如果存在,则返回false,否则返回true。根据该结果,将对象推入新数组obj中 。以上代码的输出为 [{"item_id":1},{"item_id":2}]


添加一些说明
Mathews

@Billa可以吗?
Bibin Jaimon

1

您听说过Lodash图书馆吗?如果您确实不想将逻辑应用于代码,而使用已经存在的经过优化和可靠的代码,那么我建议您使用此实用程序。

考虑制作这样的数组

things.thing.push({place:"utopia",name:"unicorn"});
things.thing.push({place:"jade_palace",name:"po"});
things.thing.push({place:"jade_palace",name:"tigress"});
things.thing.push({place:"utopia",name:"flying_reindeer"});
things.thing.push({place:"panda_village",name:"po"});

请注意,如果要保持一个属性唯一,则可以使用lodash库很好地做到这一点。在这里,您可以使用_.uniqBy

.uniqBy(array,[iteratee = .identity])

此方法类似于_.uniq(返回数组的无重复版本,其中仅保留每个元素的第一次出现),不同之处在于它接受为数组中的每个元素调用的iteratee来生成准则,计算唯一性。

因此,例如,如果您要返回一个具有“ place”唯一属性的数组

_.uniqBy(things.thing,'place')

同样,如果您希望将唯一属性用作“名称”

_.uniqBy(things.thing,'name')

希望这可以帮助。

干杯!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.