Hapus duplikat dari array

100

Saya memiliki array objek yang terlihat seperti ini:

var array = [
    {id:123, value:"value1", name:"Name1"},
    {id:124, value:"value2", name:"Name1"},
    {id:125, value:"value3", name:"Name2"},
    {id:126, value:"value4", name:"Name2"}
    ...
];

Seperti yang Anda lihat, beberapa nama diulang. Saya ingin mendapatkan array baru dengan nama saja, tetapi jika beberapa nama berulang, saya tidak ingin menambahkannya lagi. Saya ingin array ini:

var newArray = ["Name1", "Name2"];

Saya mencoba melakukan ini dengan map:

var newArray = array.map((a) => {
    return a.name;
});

Tetapi masalahnya adalah ini mengembalikan:

newArray = ["Name1", "Name1", "Name2", "Name2"];

Bagaimana saya bisa mengatur beberapa kondisi di dalam map, sehingga tidak akan mengembalikan elemen yang sudah ada? Saya ingin melakukan ini dengan mapatau beberapa fitur ECMAScript 5 atau ECMAScript 6 lainnya.

snoopy25
sumber
2
Kemudian hapus duplikat dari array.
Tushar
1
kemungkinan duplikat Hapus Duplikat dari JavaScript Array
Bergi
Mengapa baris yang berisi id: 125 tidak diakhiri dengan koma?
Peter Mortensen
Harap dicatat bahwa semua jawaban yang menggunakan .indexOf () akan memiliki kinerja yang buruk jika lariknya besar, karena kompleksitas waktu kuadratnya . Saya akan merekomendasikan menggunakan ES6 Set atau menggunakan objek ES5 sebagai kamus.
joeytwiddle

Jawaban:

210

Dengan ES6, Anda dapat menggunakan Setnilai unik, setelah memetakan hanya nama objek.

Proposal ini menggunakan sintaks menyebar... untuk mengumpulkan item dalam larik baru.

const array = [{ id: 123, value: "value1", name:"Name1" }, { id: 124, value: "value2", name: "Name1" }, { id: 125, value: "value3", name: "Name2" }, { id: 126, value: "value4", name: "Name2" }],
      names = [...new Set(array.map(a => a.name))];

console.log(names);

Nina Scholz
sumber
9
Untuk info saya .. apa yang ...dilakukan?
Rajshekar Reddy
9
@RajshekarReddy, ini adalah sintaks tersebar... untuk membangun array dengan objek yang dapat berulang.
Nina Scholz
5
Saya tidak memberikan upvoting untuk "Set" itu sendiri, melainkan untuk penggunaan operator penyebaran yang cerdik. Selalu menyenangkan untuk mempelajari sesuatu yang baru atau melihat sesuatu yang baru diterapkan pada contoh praktis, jadi posting ini layak mendapat upvote.
briosheje
33
Itu hanya pendapat pribadi saya, tapi agak umum . Menggunakan Array.frommenyampaikan maksud konversi jauh lebih baik (dan juga lebih mudah untuk memahami / mencari pemula), sintaks menyebar harus digunakan hanya di mana elemen tersebar adalah salah satu dari banyak. Mungkin menyebutnya sebagai "praktik buruk" agak terlalu kasar, maaf, saya hanya berharap untuk mencegahnya menjadi idiom umum.
Bergi
3
@KRyan adalah ES6 begitu baru? Ini telah diselesaikan pada bulan Juni 2015. Saatnya untuk mulai memahami dan menggunakan fitur baru
edc65
64

Jika Anda mencari solusi JavaScript yang tidak ES 6 (tidak ada Set) Anda dapat menggunakan Array ini reducemetode :

var array=[
  {id:123, value:"value1", name:"Name1"},
  {id:124, value:"value2", name:"Name1"},
  {id:125, value:"value3", name:"Name2"},
  {id:126, value:"value4", name:"Name2"}
];
var names = array.reduce(function (a, b) {
  if (a.indexOf(b.name) == -1) {
    a.push(b.name)
  }
  return a;
}, []);

console.log(names);

Dekel
sumber
2
Jawaban ini juga memiliki keuntungan karena tidak memerlukan array atau set perantara, terutama yang hanya berisi nama itu sendiri. (Ini pergi langsung dari array objek ke array objek.) +1
jpmc26
@Iwrestledabearonce, bukankah parameter kedua ini objek yang sama dengan yang dikembalikan?
Kaiido
Ya tetapi tidak langsung dari satu ke yang lain seperti sortir atau filter, ini dibangun kembali dari array kosong.
Aku pernah bergulat dengan beruang.
1
@Dekel - Versi yang lebih kecil :)var names = array.reduce(function(a, b) { a.indexOf(b.name) === -1 && a.push(b.name) return a; }, []);
Rayon
3
@Rayon Harap jangan terlalu memperhatikan ukuran kode sumber, ini adalah kesalahan umum bagi banyak pemrogram mandiri, yang paling penting, program Anda harus efisien dan dapat dibaca.
daun
16

Secara pribadi saya tidak mengerti mengapa semua orang menyukai ES 6. Jika itu adalah kode saya, saya lebih suka mendukung browser sebanyak mungkin.

var array=[
{id:123, value:"value1", name:"Name1"},
{id:124, value:"value2", name:"Name1"},
{id:125, value:"value3", name:"Name2"},
{id:126, value:"value4", name:"Name2"}
];

   // Create array of unique names
var a = (function(a){
  for (var i = array.length; i--;)
    if (a.indexOf(array[i].name) < 0) a.push(array[i].name);
  return a;
})([]);

console.log(a);

Saya pernah bergulat dengan beruang.
sumber
2
Bukankah akan lebih baik jika menggunakan objek sebagai kamus daripada indexOf-ing sepanjang waktu? Misalnya lakukan added[name] = truedan if(added[name])bukannya if(a.indexOf(name)).
Bojidar Marinov
7
"secara pribadi saya tidak melihat mengapa semua orang menyukai es6" mengapa Anda merayu goto fail, membocorkan variabel indeks Anda ke dalam lingkup pelingkup, dll. ES6 dikodifikasikan ke dalam standar untuk alasan yang baik, dan untuk yang paling banyak bagian sepele mudah untuk polyfill / transformasi untuk browser lama.
Jared Smith
5
Lebih mudah dibaca? Ini adalah loop freaking yang mendorong item ke array. Tidak jauh lebih mudah dibaca dari itu ......
Aku pernah bergumul dengan beruang.
4
Sejujurnya, sepertinya Anda berusaha terlalu keras untuk menemukan sesuatu untuk dikeluhkan.
Aku pernah bergulat dengan beruang.
2
"Saya mengacu pada bug SSL Apple yang terkenal" - Tidak terlalu terkenal bahwa Anda hanya dapat pergi dan merujuknya dalam komentar acak di luar konteks dan mengharapkan orang untuk mengenalinya.
Hejazzman
14

Anda juga bisa menggabungkan mapdenganfilter

var array = [
  {id:123, value:"value1", name:"Name1"},
  {id:124, value:"value2", name:"Name1"},
  {id:125, value:"value3", name:"Name2"},
  {id:126, value:"value4", name:"Name2"}
];

var unique = array
  .map( item => item.name )
  .filter( ( item, idx, arr ) => arr.indexOf( item ) == idx ) 

console.log(unique)

DavidDomain
sumber
11

Anda bisa menggunakan Object.keys () untuk mendapatkan array nama properti enumerable objek tertentu dari hasil objek arrayvariabel iterasi dengan Array.prototype.reduce () di mana kuncinya adalah nama yang dirusak

Kode:

const array = [{id:123, value:"value1", name:"Name1"}, {id:124, value:"value2", name:"Name1"}, {id:125, value:"value3", name:"Name2"}, {id:126, value:"value4", name:"Name2"}],
      names = Object.keys(array.reduce((a, { name }) => (a[name] = 1, a), {}))

console.log(names)

Yosvel Quintero Arguelles
sumber
7

Banyak jawaban bagus di sini. Saya hanya ingin berkontribusi dengan beberapa keragaman dengan harapan memberi Anda perspektif lain.

Array adalah tipe objek dalam JavaScript, sehingga bisa digunakan sebagai hash pada saat yang bersamaan. Dengan menggunakan fungsionalitas ini kita dapat sangat menyederhanakan pekerjaan yang akan dilakukan dalam satu operasi pengurangan dengan kompleksitas waktu O (n).

Jika Anda tidak senang dengan array Anda yang memiliki beberapa properti selain kunci array Anda mungkin mempertimbangkan untuk menyimpan objek hash yang terpisah juga.

var array = [{id:123, value:"value1", name:"Name1"},
             {id:124, value:"value2", name:"Name1"},
             {id:125, value:"value3", name:"Name2"},
             {id:126, value:"value4", name:"Name2"}
            ],
result = array.reduce((p,c) => p[c.name] ? p : (p[c.name] = true, p.push(c.name), p), []);
console.log(result);

Redu
sumber
Solusi ES5 ini memiliki performa yang baik, tetapi menggunakan array untuk dua tujuan akan membingungkan, dan berbahaya jika salah satu namanya hanya berupa angka. Saya akan merekomendasikan melakukan p[c.name]hal - hal tersebut pada objek terpisah odan kemudian membuangnya setelah itu.
joeytwiddle
7

Saya setuju bahwa jika Anda hanya membutuhkan namenilai, a Setadalah jalan yang harus ditempuh.

Namun , jika Anda ingin mendapatkan larik objek unik berdasarkan nameproperti, saya sarankan untuk menggunakan file Map. Cara cepat untuk membuat Peta, adalah melalui array [key, value]array:

const array = [{ id: 123, value: "value1", name:"Name1" }, { id: 124, value: "value2", name: "Name1" }, { id: 125, value: "value3", name: "Name2" }, { id: 126, value: "value4", name: "Name2" }],
      unique = new Map(array.map(obj => [obj.name, obj]));

// To get the unique objects
const uniques = Array.from(unique.values());

// Get the names like you already did:
console.log("Names:", uniques.map(obj => obj.name));

// If you ever need the complete array of unique objects, you got a ref:
console.log(JSON.stringify(uniques));
.as-console-wrapper { min-height: 100%; }

Manfaat tambahannya Mapadalah Anda mendapatkan filterfungsionalitas yang menghilangkan non-unik, tanpa kehilangan koneksi dengan objek sumber. Tentu saja, ini hanya diperlukan jika Anda perlu mereferensikan kumpulan objek unik beberapa kali.

pengguna3297291
sumber
3

Jika Anda terbatas pada ES5, saya akan menggunakan Lodash_.uniq

var newArray = _.uniq(array.map(function(a) {
  return a.name;
}));
AndrewHenderson
sumber
2

Dengan ES6 ini harus melakukan pekerjaan itu.

var array=[
    {id:123, value:"value1", name:"Name1"},
    {id:124, value:"value2", name:"Name1"},
    {id:125, value:"value3", name:"Name2"},
    {id:126, value:"value4", name:"Name2"}
];

var set = new Set();

array.forEach((a)=>{
    set.add(a.name);
}); 

console.log(Array.from(set));

kkreft.dll
sumber
11
mapseharusnya digunakan dengan fungsi murni, bukan untuk memiliki efek samping. Ini akan menjadi pekerjaan untuk forEachatau reduce.
Vincent van der Weele
1

Menggunakan UnderscoreJS,

array = [{id:123, value:"value1", name:"Name1"}, {id:124, value:"value2", name:"Name1"}, {id:125, value:"value3", name:"Name2"}, {id:126, value:"value4", name:"Name2"}];
get_names =  _.pluck(_.uniq(array, 'name'), 'name')
console.log(get_names)
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>

`

Mohideen bin Mohammed
sumber
0

Di ES5, gunakan objek sebagai kamus untuk kinerja O ( n ).

Ini hanya akan berfungsi jika semua kuncinya adalah String.

var array = [
    {id: 123, value: "value1", name: "Name1"},
    {id: 124, value: "value2", name: "Name1"},
    {id: 125, value: "value3", name: "Name2"},
    {id: 126, value: "value4", name: "Name2"}
];

var allNames = array.map(item => item.name);

var map = {};
allNames.forEach(name => {
  map[name] = true;
});
var uniqueNames = Object.keys(map);

console.log(uniqueNames);

Anda dapat melakukan hal yang sama dalam satu ekspresi jika Anda suka:

var uniqueNames = Object.keys(allNames.reduce((m, n) => (m[n] = true, m), {}));

tetapi saya merasa bentuk imperatifnya lebih mudah dibaca.

joeytwiddle
sumber
Saya menggunakan fungsi panah ES6 untuk kejelasan. Jika Anda benar-benar menargetkan ES5 tanpa transpiler, Anda perlu menggunakan formulir lengkap sebagai gantinya:function (item) { return item.name; }
joeytwiddle
Sebagai alternatif Object.keys(), jawaban ini hanya digunakan filter()untuk menyimpan nama-nama yang belum disimpan di peta, yang cukup elegan.
joeytwiddle
0

Coba ini:

nArr = [];
array.forEach((a) => {
    if (nArr.indexOf(a.name) < 0) { 
        nArr.push(a.name); 
    }
}); 
Rafael Gomes Francisco
sumber
0

Gunakan array#forEach()dan array#indexOf()metode seperti ini jika Anda ingin kompatibilitas maksimum , sintaks singkat:

const array = [{ id: 123, value: "value1", name:"Name1" }, { id: 124, value: "value2", name: "Name1" }, { id: 125, value: "value3", name: "Name2" }, { id: 126, value: "value4", name: "Name2" }]

// initialize an empty array named names
let names = [];

// iterate through every element of `array` & check if it's 'name' key's value already in names array if not ADD it 
array.forEach(function(element) { if (names.indexOf(element.name) === -1) names.push(element.name) });
// or use tilde like this:
//array.forEach(function(element) { if (~names.indexOf(element.name)) names.push(element.name) });

console.log(names);

Namun, jika kompatibilitas adalah bukan masalah penggunaan ECMAScript 6 's Setobjek, array#mapdan Array.from()metode seperti ini:

const array = [{ id: 123, value: "value1", name:"Name1" }, { id: 124, value: "value2", name: "Name1" }, { id: 125, value: "value3", name: "Name2" }, { id: 126, value: "value4", name: "Name2" }];

// iterate through every element from array using map and store it in Set(a Set won't have duplicates) then convert the Set back to Array(using Array.from)
let names = Array.from(new Set(array.map(element => element.name)));

console.log(names);

BlackBeard
sumber
0

Begitulah cara saya melakukannya, menggunakan array kosong yang terpisah.

var array = [
   {id:123, value:"value1", name:"Name1"},
   {id:124, value:"value2", name:"Name1"},
   {id:125, value:"value3", name:"Name2"},
   {id:126, value:"value4", name:"Name2"}	    
];

var array2 = []		
		
for (i=0; i<array.length;i++){						
   if (array2.indexOf(array[i].name) == -1){				
     array2.push(array[i].name);
    }
}			

console.log(array2)	

Abhishek Gurjar
sumber
-1

Bagi mereka yang mencari 1 liner

const names = array.reduce((acc, {name}) => acc.includes(name) ? acc : [name, ...acc], []);

atau tanpa menggunakan metode pada prototipe larik

const { reduce, includes } = Array;
const names = reduce(array, (acc, {name}) => includes(acc, name) ? acc : [name, ...acc], []);

bisa berguna untuk menulis beberapa fungsi murni untuk menangani ini

const get_uniq_values = (key, arr) => reduce(arr, (a, o) => includes(a, o[key]) ? a : [o[key], ...a], []);
Tyrell
sumber
-1
var __array=[{id:123, value:"value1", name:"Name1"},{id:124, value:"value2", name:"Name1"},{id:125, value:"value3", name:"Name2"},{id:126, value:"value4", name:"Name2"}];

function __checkArray(__obj){
    var flag = true;
    for(let i=0; i < __array.length; i++){
        if(__obj.id == __array.id){
            flag = false;
            break;
        }
    }

    return flag;
}

var __valToPush = {id: 127, value: "value5", name: "Name3"};
if(__checkArray(__valToPush)){
    __array.push(__valToPush)
}
AKHIL
sumber
11
apakah Anda punya alasan khusus untuk menggunakan begitu banyak garis bawah?
Nina Scholz