Xóa các bản sao khỏi một mảng các đối tượng trong JavaScript


373

Tôi có một đối tượng có chứa một mảng các đối tượng.

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

Tôi đang tự hỏi đâu là phương pháp tốt nhất để loại bỏ các đối tượng trùng lặp khỏi một mảng. Vì vậy, ví dụ, mọi thứ. Mọi thứ sẽ trở thành ...

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

Bạn có nghĩa là làm thế nào để bạn dừng một hashtable / object với tất cả các tham số tương tự được thêm vào một mảng?
Khóa Matthew

1
Mathew -> Nếu đơn giản hơn để ngăn chặn một đối tượng trùng lặp được thêm vào mảng ở vị trí đầu tiên, thay vì lọc nó ra sau, vâng, điều đó cũng sẽ ổn.
Travis

2
Nó làm tôi ngạc nhiên về cách mọi người đặt tên cho biến của họ. Đôi khi tôi nghĩ rằng họ thực sự muốn làm cho nó phức tạp không cần thiết. Tiếp theo để xem sẽ aaaaa.aaaa.push(...):)
dazito

Câu trả lời:


154

Một phương pháp nguyên thủy sẽ là:

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
Bạn không bao giờ nên sử dụng độ dài trong vòng lặp for, vì nó sẽ làm chậm mọi thứ khi tính toán nó trên mỗi lần lặp. Gán nó cho một biến bên ngoài vòng lặp và truyền biến thay vì các thứ.thing.length.
0v3rth3d4wn

12
@aefxx Tôi không hiểu rõ chức năng này, làm thế nào để bạn xử lý tình huống "địa điểm" giống nhau nhưng tên khác nhau, có nên xem xét song công hay không?
Kuan

2
Mặc dù điều này hoạt động, nó không quan tâm đến một mảng được sắp xếp vì các khóa tìm nạp không bao giờ được đảm bảo. Vì vậy, cuối cùng bạn sắp xếp lại nó. Bây giờ, giả sử mảng không được sắp xếp nhưng thứ tự của nó rất quan trọng, không có cách nào bạn có thể đảm bảo rằng thứ tự đó vẫn còn nguyên
Deepak GM

1
@DeepakGM Bạn hoàn toàn đúng. Câu trả lời sẽ không (nhất thiết) bảo tồn một trật tự nhất định. Nếu đó là một yêu cầu, người ta nên tìm một giải pháp khác.
aefxx

Làm thế nào tôi có thể sửa đổi ở trên để loại bỏ các đối tượng khỏi một mảng có chứa X cũng như được sao chép lại?
Ryan Holton

435

Làm thế nào với một số es6phép thuật?

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

URL tham chiếu

Một giải pháp chung hơn sẽ là:

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

Ví dụ về Stackblitz


81
Điều này có thể được rút ngắn thành:things.thing = things.thing.filter((thing, index, self) => self.findIndex(t => t.place === thing.place && t.name === thing.name) === index)
Josh Cole

Hoạt động hoàn hảo! var uniqueArrayOfObjects = ArrayOfObjects.filter (function (obj, index, self) {return index === self.findIndex (function (t) {return t ['obj-property'] === obj ['obj-property'] });}); Hãy chắc chắn rằng bạn sử dụng cú pháp JS thích hợp.
Mohamed Salem Lamiri

Đó là những cú pháp JS thích hợp. Bạn không sử dụng 1) chức năng mũi tên béo 2) hoàn trả ẩn hoặc 3) ký hiệu dấu chấm. Cú pháp của bạn là ES5. Những cái khác chủ yếu là ES6 (ECMA2015). Tất cả đều có giá trị trong năm 2017. Xem bình luận của jaredwilli.
agm1984

8
@vsync chỉ cần lấy câu trả lời của @ BKM và đặt nó lại với nhau, một giải pháp chung sẽ là: const uniqueArray = arrayOfObjects.filter((object,index) => index === arrayOfObjects.findIndex(obj => JSON.stringify(obj) === JSON.stringify(object))); jsfiddle.net/x9ku0p7L/28
Eydrian 18/07/18

9
Chìa khóa ở đây là phương thức find Index () trả về chỉ mục của phần tử đầu tiên , vì vậy nếu có phần tử thứ hai khớp, nó sẽ không bao giờ được tìm thấy và thêm vào trong bộ lọc. Tôi đã nhìn chằm chằm vào nó một phút :)
JBaczuk

111

Nếu bạn có thể sử dụng các thư viện Javascript như gạch dưới hoặc lodash, tôi khuyên bạn nên xem _.uniqchức năng trong thư viện của họ. Từ lodash:

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

Về cơ bản, bạn truyền vào mảng mà ở đây là một đối tượng bằng chữ và bạn chuyển vào thuộc tính mà bạn muốn loại bỏ trùng lặp trong mảng dữ liệu gốc, như sau:

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

CẬP NHẬT : Lodash bây giờ cũng đã giới thiệu một .uniqBy.


3
@Praveen Pds: Tôi có nói gì về dấu gạch dưới trong ví dụ mã không? Tôi đã nói 'lodash' có chức năng này và gạch dưới có những cái tương tự. Trước khi bỏ phiếu, xin vui lòng đọc câu trả lời cẩn thận.
ambodi

// Liệt kê các đối tượng duy nhất bằng cách sử dụng _underscore.js HoldObject = _.uniq (HoldObject, function (item, key, name) {return item.name;});
khen ngợi

26
Lưu ý: bây giờ bạn cần sử dụng uniqBythay vì uniq, ví dụ _.uniqBy(data, 'name')... tài liệu: lodash.com/docs#uniqBy
drmrbrewer

83

Tôi đã có yêu cầu chính xác này, để loại bỏ các đối tượng trùng lặp trong một mảng, dựa trên các bản sao trên một trường duy nhất. Tôi đã tìm thấy mã ở đây: Javascript: Loại bỏ trùng lặp khỏi mảng đối tượng

Vì vậy, trong ví dụ của tôi, tôi đang xóa bất kỳ đối tượng nào khỏi mảng có giá trị chuỗi LicenseNum trùng lặp.

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

Kết quả:

UniqueArray là:

[{"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
Điều này sẽ hữu ích hơn nếu chức năng cũng có thể lọc các đối tượng 'giả mạo'. for(var i in array) { if(array[i][prop]){ //valid lookupObject[array[i][prop]] = array[i]; } else { console.log('falsy object'); } }
Abdul Sadik Yalcin

Tại sao không giảm độ phức tạp 0 (n) bằng cách sử dụng: for (let i in originalArray) { if (lookupObject[originalArray[i]['id']] === undefined) { newArray.push(originalArray[i]); } lookupObject[originalArray[i]['id']] = originalArray[i]; }
Tudor B.

Đây là cách tốt nhất vì điều quan trọng là phải biết những gì bạn muốn không bị trùng lặp. Bây giờ điều này có thể được thực hiện thông qua bộ giảm tốc cho các tiêu chuẩn e6?
Christian Matthew

69

Một lớp lót ngắn nhất cho ES6 +

Tìm duy nhất idtrong một mảng.

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

Duy nhất bởi nhiều thuộc tính ( placename)

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

Duy nhất bởi tất cả các thuộc tính (Điều này sẽ chậm đối với các mảng lớn)

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

Giữ lần xuất hiện cuối cùng

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

2
Phép thuật, đây là câu trả lời thực sự
Luis Tương phản

48

Một lớp lót sử dụng Set

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)

Giải trình:

  1. new Set(myData.map(JSON.stringify))tạo một đối tượng Set bằng cách sử dụng các phần tử myData được xâu chuỗi.
  2. Đặt đối tượng sẽ đảm bảo rằng mọi phần tử là duy nhất.
  3. Sau đó, tôi tạo một mảng dựa trên các phần tử của tập đã tạo bằng Array.from.
  4. Cuối cùng, tôi sử dụng JSON.parse để chuyển đổi phần tử được xâu chuỗi trở lại một đối tượng.

18
vấn đề là {a: 1, b: 2} sẽ không bằng {b: 2, a: 1}
PirateApp

2
Hãy nhớ rằng sẽ có vấn đề với các thuộc tính Ngày
MarkosyanArtur

Dòng này tạo các giá trị null ngẫu nhiên với một đối tượng hàng không tồn tại trong mảng ban đầu của các đối tượng. Bạn có thể vui lòng giúp đỡ?
B1K

46

Sử dụng ES6 + trong một dòng duy nhất, bạn có thể nhận được một danh sách các đối tượng duy nhất theo khóa:

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

Nó có thể được đưa vào một chức năng:

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

Dưới đây là một ví dụ hoạt động:

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

Làm thế nào nó hoạt động

Đầu tiên, mảng được ánh xạ lại theo cách nó có thể được sử dụng làm đầu vào cho Bản đồ.

mảng.map (mục => [mục [khóa], mục]);

có nghĩa là mỗi mục của mảng sẽ được chuyển đổi trong một mảng khác có 2 phần tử; các khóa đã chọn như yếu tố đầu tiên và toàn bộ mục ban đầu như Yếu tố thứ hai, điều này được gọi là (ví dụ. entry mục mảng , mục bản đồ ). Và đây là tài liệu chính thức với một ví dụ chỉ ra cách thêm các mục mảng trong hàm tạo Map.

Ví dụ khi khóa được đặt :

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

Thứ hai, chúng tôi chuyển mảng đã sửa đổi này cho hàm tạo Map và đây là điều kỳ diệu xảy ra. Bản đồ sẽ loại bỏ các giá trị khóa trùng lặp, chỉ giữ giá trị được chèn cuối cùng của cùng một khóa. Lưu ý : Bản đồ giữ thứ tự chèn. ( kiểm tra sự khác biệt giữa Bản đồ và đối tượng )

Bản đồ mới (mảng nhập vừa được ánh xạ ở trên)

Thứ ba, chúng tôi sử dụng các giá trị bản đồ để lấy các mục gốc, nhưng lần này không có sự trùng lặp.

Bản đồ mới (mappedArr) .values ​​()

Và cuối cùng là thêm các giá trị đó vào một mảng mới để nó có thể trông giống như cấu trúc ban đầu và trả về:

trả về [... Bản đồ mới (mappedArr) .values ​​()]


Điều này không trả lời câu hỏi ban đầu vì đây là tìm kiếm cho một id. Câu hỏi cần toàn bộ đối tượng là duy nhất trên tất cả các lĩnh vực như placename
L. Holanda

Chức năng ES6 của bạn có vẻ rất súc tích và thực tế. Bạn có thể giải thích thêm một chút không? Điều gì đang xảy ra chính xác? Là bản sao đầu tiên hoặc cuối cùng được loại bỏ? Hoặc là ngẫu nhiên, bản sao nào được gỡ bỏ? Điều đó sẽ hữu ích, cảm ơn.
David Schumann

Theo như tôi có thể nói, một Bản đồ với giá trị thuộc tính là khóa được tạo. Nhưng nó không phải là 100% như thế nào hoặc nếu thứ tự của mảng được bảo tồn.
David Schumann

1
Xin chào @DavidSchumann, tôi sẽ cập nhật câu trả lời và sẽ giải thích cách thức hoạt động của nó. Nhưng để trả lời ngắn gọn, thứ tự được giữ nguyên và cái đầu tiên bị xóa ... Chỉ cần nghĩ về cách nó được chèn vào bản đồ ... nó kiểm tra xem khóa đã tồn tại chưa, nó sẽ cập nhật nó, vì vậy cái cuối cùng sẽ vẫn còn
V Sambor

30

Đây là một tùy chọn khác để thực hiện bằng các phương pháp lặp Array nếu bạn chỉ cần so sánh theo một trường của một đối tượng:

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

Mặc dù giá trị này có đơn hàng lớn hơn O (n²), nhưng điều này phù hợp với trường hợp sử dụng của tôi vì kích thước mảng của tôi sẽ luôn nhỏ hơn 30. Cảm ơn!
Sterex

24

một lớp lót ở đây

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
Đẹp và sạch sẽ nếu bạn chỉ muốn xóa các đối tượng với một giá trị trùng lặp duy nhất, không sạch sẽ cho các đối tượng trùng lặp hoàn toàn.
David Barker

22

Nếu bạn có thể chờ để loại bỏ các bản sao cho đến sau tất cả các bổ sung, cách tiếp cận điển hình là trước tiên sắp xếp mảng và sau đó loại bỏ các bản sao. Việc sắp xếp sẽ tránh cách tiếp cận N * N khi quét mảng cho từng phần tử khi bạn đi qua chúng.

Hàm "loại bỏ trùng lặp" thường được gọi là duy nhất hoặc uniq . Một số triển khai hiện có có thể kết hợp hai bước, ví dụ: uniq nguyên mẫu

Bài đăng này có một vài ý tưởng để thử (và một số để tránh :-)) nếu thư viện của bạn chưa có ! Cá nhân tôi thấy điều này là thẳng nhất:

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

Điều đó sẽ không làm việc cho các đối tượng chung mà không có thứ tự sắp xếp tự nhiên.
Tim Down

Đúng, tôi đã thêm một phiên bản so sánh do người dùng cung cấp.
maccullt

Phiên bản so sánh do người dùng cung cấp của bạn sẽ không hoạt động vì nếu chức năng so sánh của bạn function(_a,_b){return _a.a===_b.a && _a.b===_b.b;}thì mảng sẽ không được sắp xếp.
graham.reeds

1
Đó là một chức năng so sánh không hợp lệ. Từ developer.mozilla.org/en/Core_JavaScript_1.5_Reference/, ... so sánh hàm (a, b) {if (a nhỏ hơn b bởi một số tiêu chí đặt hàng) return -1; if (a lớn hơn b theo tiêu chí đặt hàng) trả về 1; // a phải bằng b trả về 0; } ...
maccullt

22

Cách đơn giản nhất là sử dụng 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
Đó là một thực hành tốt trên Stack Overflow để thêm một lời giải thích về lý do tại sao giải pháp của bạn nên hoạt động, đặc biệt là cách bạn giải quyết tốt hơn các câu trả lời khác. Để biết thêm thông tin đọc Làm thế nào để trả lời .
Samuel Liew

Điều này không trả lời câu hỏi ban đầu vì đây là tìm kiếm cho một id. Câu hỏi cần toàn bộ đối tượng là duy nhất trên tất cả các lĩnh vực như placename
L. Holanda

17

Đây là một cách chung để làm điều này: bạn truyền vào một hàm kiểm tra xem hai phần tử của một mảng có được coi là bằng nhau hay không. Trong trường hợp này, nó so sánh các giá trị của nameplace thuộc tính của hai đối tượng được so sánh.

Câu trả lời 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);

Câu trả lời ES3 gốc

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
Hai đối tượng sẽ không đánh giá bằng nhau, ngay cả khi chúng có chung các thuộc tính và giá trị.
kennebec

Vâng tôi biết. Nhưng công bằng mà nói, tôi đã không đọc chính xác câu hỏi: Tôi đã không phát hiện ra rằng đó là những vật thể có đặc tính giống hệt anh ta cần loại bỏ. Tôi sẽ chỉnh sửa câu trả lời của tôi.
Tim Down

1
thay vì trong khi bên trong mảngContains- sử dụng Array.prototype..some phương thức Trả về true nếu một trong các thành viên mảng khớp với điều kiện
MarkosyanArtur

13

Để thêm một danh sách nữa. Sử dụng ES6 và Array.reducevới Array.find.
Trong ví dụ này lọc các đối tượng dựa trên một thuộc guidtính.

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

Mở rộng cái này để cho phép lựa chọn một thuộc tính và nén nó vào một lớp lót:

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

Để sử dụng, nó vượt qua một mảng các đối tượng và tên của khóa mà bạn muốn hủy mã thành một giá trị chuỗi:

const result = uniqify(myArrayOfObjects, 'guid')

11

Bạn cũng có thể sử dụng Map:

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

Mẫu đầy đủ:

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

Kết quả:

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

+1, tốt đẹp giải thích thêm một chút về hoạt động bên trong của các khoản khấu trừ. Điều đó sẽ tốt - về mặt tươi sáng, giờ tôi đã hiểu giảm: D
MimiEAM

11

Dang, bọn trẻ, chúng ta hãy nghiền nát thứ này, tại sao chúng ta không?

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'}];


Điều này không trả lời câu hỏi ban đầu vì đây là tìm kiếm cho một id. Câu hỏi cần toàn bộ đối tượng là duy nhất trên tất cả các lĩnh vực như placename
L. Holanda

Đây là một sàng lọc của một khái quát ở trên của vấn đề. Câu hỏi ban đầu đã được đăng 9 năm trước, vì vậy người đăng ban đầu có lẽ không lo lắng placenamengày nay. Bất cứ ai đọc chủ đề này đều tìm kiếm một cách tối ưu để trích ra một danh sách các đối tượng và đây là một cách làm nhỏ gọn.
Hội trường Cliff

11

Một giải pháp TypeScript

Điều này sẽ loại bỏ các đối tượng trùng lặp và cũng bảo tồn các loại đối tượng.

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

2
Điều này thật tuyệt và ngắn!
mojjj

Và siêu chậm quá ...
L. Holanda

7

Xem xét 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 }]

Hoàn hảo ! Cảm ơn bạn ;-)
DonFabiolas

1
Cả uniq và uniqBy của lodash đều không lừa, nhưng giải pháp của bạn thì có. Cảm ơn! Vui lòng cung cấp nguồn mã của bạn, tuy nhiên, nếu đó là bản sao trực tiếp. lodash.com/docs/4.17.10#uniqWith
Manu CJ

5

Một tùy chọn khác là tạo một hàm indexOf tùy chỉnh, so sánh các giá trị của thuộc tính bạn đã chọn cho từng đối tượng và bọc hàm này trong hàm giảm.

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;
    },[]);

điều này rất tốt cho tôi - tôi đã ghép nối nó với lodash.isequalgói npm như một bộ so sánh đối tượng nhẹ để thực hiện lọc mảng duy nhất ... ví dụ: mảng đối tượng khác biệt. Chỉ cần hoán đổi if (_.isEqual(a[i], b)) {thay vì tìm @ một tài sản duy nhất
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)

Một lớp lót sử dụng ES6 và new Map().

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

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

Chi tiết:-

  1. Thực hiện .map()trên danh sách dữ liệu và chuyển đổi từng đối tượng riêng lẻ thành một [key, value]mảng cặp (length = 2), phần tử đầu tiên (khóa) sẽ làstringified phiên bản của đối tượng và thứ hai (giá trị) sẽ là mộtobject chính nó.
  2. Thêm danh sách mảng đã tạo ở trên new Map()sẽ có khóa nhưstringified đối tượng và bất kỳ phép cộng khóa nào tương tự sẽ dẫn đến ghi đè khóa đã tồn tại.
  3. Việc sử dụng .values()sẽ cung cấp cho MapIterator với tất cả các giá trị trong Bản đồ (obj trong trường hợp của chúng tôi)
  4. Cuối cùng, spread ...toán tử đưa ra Mảng mới với các giá trị từ bước trên.

4

Đây là một giải pháp cho es6, nơi bạn chỉ muốn giữ mục cuối cùng. Giải pháp này phù hợp với chức năng và kiểu 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' }]

Bạn có thể loại bỏ trùng lặp và bạn cũng có thể xóa tất cả các bản sao với mã này. Đẹp
sg28

4

removeD repeatates () nhận một mảng các đối tượng và trả về một mảng mới mà không có bất kỳ đối tượng trùng lặp nào (dựa trên thuộc tính 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);

Kết quả dự kiến:

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

Đầu tiên, chúng ta đặt giá trị của biến uniq thành một đối tượng trống.

Tiếp theo, chúng tôi lọc qua mảng các đối tượng. Bộ lọc tạo ra một mảng mới với tất cả các yếu tố vượt qua bài kiểm tra được thực hiện bởi hàm được cung cấp.

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

Ở trên, chúng tôi sử dụng chức năng ngắn mạch của &&. Nếu bên trái của && ước tính là đúng, thì nó sẽ trả về giá trị ở bên phải của &&. Nếu bên trái là sai, nó sẽ trả về những gì ở bên trái của &&.

Đối với mỗi đối tượng (obj), chúng tôi kiểm tra uniq cho một thuộc tính có tên là giá trị của obj.id (Trong trường hợp này, trong lần lặp đầu tiên, nó sẽ kiểm tra thuộc tính '1'.) Chúng tôi muốn ngược lại với những gì nó trả về (đúng hoặc sai) đó là lý do tại sao chúng tôi sử dụng! trong! uniq [obj.id]. Nếu uniq đã có thuộc tính id, nó sẽ trả về true, ước lượng thành false (!) Nói với hàm bộ lọc KHÔNG thêm obj đó. Tuy nhiên, nếu nó không tìm thấy thuộc tính obj.id, nó sẽ trả về false, sau đó đánh giá là true (!) Và trả lại mọi thứ ở bên phải của &&, hoặc (uniq [obj.id] = true). Đây là một giá trị trung thực, nói cho phương thức bộ lọc thêm obj đó vào mảng được trả về và nó cũng thêm thuộc tính {1: true} vào uniq. Điều này đảm bảo rằng bất kỳ trường hợp obj nào khác có cùng id đó sẽ không được thêm lại.


Có lẽ giải thích mã của bạn, và làm thế nào nó trả lời câu hỏi?
mix3d

Cảm ơn, mix3d. Tôi nói thêm làm rõ.
MarkN

Cảm ơn đã giải thích điều này! Giải pháp này hiệu quả với tôi và tương tự như một vài người khác được đăng ở đây, mặc dù tôi không hiểu chuyện gì đang xảy ra :)
Tim Molloy

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

9
Vui lòng thêm một lời giải thích xung quanh mã của bạn để khách truy cập trong tương lai có thể hiểu bạn đang làm gì. Cảm ơn.
Lỗi

Câu trả lời của bạn phụ thuộc vào thư viện mã bên ngoài ...
Taylor A. Leach

3

Tôi tin rằng sự kết hợp reducevới JSON.stringifyđể so sánh hoàn hảo các Đối tượng và thêm chọn lọc những người chưa có trong bộ tích lũy là một cách thanh lịch.

Hãy nhớ rằng JSON.stringifycó thể trở thành một vấn đề hiệu năng trong các trường hợp cực đoan trong đó mảng có nhiều Đối tượng và chúng rất phức tạp, NHƯNG trong phần lớn thời gian , đây là cách ngắn nhất để đi IMHO.

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)

Một cách viết khác giống nhau (nhưng kém hiệu quả hơn):

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

một trong đó làm việc cho tôi! cảm ơn bạn!
javascript110899

2

Tiếp tục khám phá các cách ES6 để loại bỏ các bản sao khỏi mảng các đối tượng: thiết lập thisArgđối số Array.prototype.filterđể new Setcung cấp một sự thay thế hợp lý:

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

Tuy nhiên, nó sẽ không hoạt động với các hàm mũi tên () =>, như thisbị ràng buộc với phạm vi từ vựng của chúng.


2

ma thuật es6 trong một dòng ... có thể đọc được ở đó!

// 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

Giải pháp đơn giản với các phương thức trợ giúp mảng ES6 'giảm' và 'tìm'

Hoạt động hiệu quả và hoàn toàn tốt!

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

Điều này đã giúp tôi rất nhiều, cảm ơn bạn
jpisty

1

Nếu bạn không nhớ mảng duy nhất của mình sẽ được sắp xếp sau đó, đây sẽ là một giải pháp hiệu quả:

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

Bằng cách này, bạn chỉ phải so sánh phần tử hiện tại với phần tử trước đó trong mảng. Sắp xếp một lần trước khi lọc ( O(n*log(n))) rẻ hơn so với tìm kiếm một bản sao trong toàn bộ mảng cho mọi phần tử mảng ( O(n²)).


1

Đây là cách đơn giản để loại bỏ sự trùng lặp khỏi mảng các đối tượng.

Tôi làm việc với dữ liệu rất nhiều và điều này hữu ích cho tôi.

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

sẽ in ra bàn điều khiển:

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

Giải pháp này được thiết kế để loại bỏ trùng lặp khỏi mảng tĩnh, nhưng khi bạn đẩy dữ liệu từ phụ trợ vào mảng dữ liệu thì hãy cân nhắc sử dụng thay thế. Bởi vì trong trường hợp này, giá trị mới được đẩy vào mảng dữ liệu sẽ bị xóa và giá trị "cũ" sẽ vẫn được lưu trong mảng dữ liệu.
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 là một mảng các đối tượng. Tồn tại các đối tượng có cùng giá trị (ở đây một ví dụ nhỏ, có hai đối tượng có cùng item_id là 2). check (id) là một hàm kiểm tra xem có đối tượng nào có cùng item_id tồn tại hay không. nếu nó tồn tại trả về false nếu không trả về true. Theo kết quả đó, đẩy đối tượng vào một mảng mới obj Đầu ra của đoạn mã trên là [{"item_id":1},{"item_id":2}]


Thêm một số mô tả
Mathews Sunny

@Billa Có ổn không?
Bibin Jaimon

1

Bạn đã nghe nói về thư viện Lodash? Tôi khuyên bạn nên sử dụng tiện ích này, khi bạn không thực sự muốn áp dụng logic của mình vào mã và sử dụng mã đã có sẵn được tối ưu hóa và đáng tin cậy.

Hãy xem xét việc tạo một mảng như thế này

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

Lưu ý rằng nếu bạn muốn giữ một thuộc tính duy nhất, bạn rất có thể làm điều đó bằng cách sử dụng thư viện lodash. Tại đây, bạn có thể sử dụng _.uniqBy

.uniqBy (mảng, [iteratee = .identity])

Phương thức này giống như _.uniq (trả về một phiên bản không có bản sao của một mảng, trong đó chỉ có lần xuất hiện đầu tiên của mỗi phần tử được giữ) ngoại trừ việc nó chấp nhận iteratee được gọi cho mỗi phần tử trong mảng để tạo tiêu chí theo đó tính độc đáo được tính toán.

Vì vậy, ví dụ, nếu bạn muốn trả về một mảng có thuộc tính duy nhất là 'địa điểm'

_.uniqBy (điều. mọi thứ, 'địa điểm')

Tương tự, nếu bạn muốn thuộc tính duy nhất là 'tên'

_.uniqBy (điều. mọi thứ, 'tên')

Hi vọng điêu nay co ich.

Chúc mừng!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.