Menghapus objek duplikat dengan Garis Bawah untuk Javascript


124

Saya memiliki jenis array ini:

var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];

Saya ingin memfilternya agar memiliki:

var bar = [ { "a" : "1" }, { "b" : "2" }];

Saya mencoba menggunakan _.uniq, tapi saya rasa karena { "a" : "1" }tidak sama dengan dirinya sendiri, itu tidak berhasil. Apakah ada cara untuk memberikan garis bawah uniq dengan fungsi yang sama dengan yang diganti?


Silakan kirim kode Anda juga
Chetter Hummin

Apakah hal-hal seperti itu { "a" : "2" }ada? Jika demikian, apakah atribut atau nilai yang membuatnya unik?
Matt

Ya, saya memang memiliki atribut sebagai kunci, saya menerapkan indeks yang ditunjukkan seseorang kepada saya pada topik lain, tetapi kemudian saya ingin membersihkan kode saya menggunakan beberapa perpustakaan umum
plus-

1
Pleae mengubah jawaban yang diterima.
Vadorequest

Jawaban:


232

.uniq / .unique menerima panggilan balik

var list = [{a:1,b:5},{a:1,c:5},{a:2},{a:3},{a:4},{a:3},{a:2}];

var uniqueList = _.uniq(list, function(item, key, a) { 
    return item.a;
});

// uniqueList = [Object {a=1, b=5}, Object {a=2}, Object {a=3}, Object {a=4}]

Catatan:

  1. Nilai kembali panggilan balik digunakan untuk perbandingan
  2. Objek perbandingan pertama dengan nilai pengembalian unik digunakan sebagai unik
  3. underscorejs.org tidak mendemonstrasikan penggunaan callback
  4. lodash.com menunjukkan penggunaan

Contoh lain: menggunakan callback untuk mengekstrak merek mobil, warna dari daftar


falsetidak diperlukan untuk _.uniq(). Juga di lodash Anda bisa menulisnya seperti ini _.uniq(a, 'a');, karena itu akan menarik properti apada objek.
Larry Battle

The "'_.pluck' callback shorthand" hanya berfungsi jika Anda memberikan nilai untuk isSorted (misalnya _.uniq(a, false, 'a')) Saya melakukan ping ke github / bestiejs / lodash dan mereka mengatakan bahwa masalah telah diperbaiki. Jadi jika Anda tidak menggunakan suatu fungsi, pastikan Anda memiliki yang terbaru. Ini mungkin bukan masalah untuk garis bawah.
Shanimal

2
Iterator tidak terdengar seperti nama yang bagus, ini adalah fungsi seperti hash yang akan menentukan identitas setiap objek
Juan Mendes

Diedit untuk menggunakan callback agar lebih konsisten dengan dokumen lodash :)
Shanimal

1
Anda contoh di jsbin dapat memiliki pembaruan. (1) Membuat: _ (mobil) .uniq ('make'). Map ('make'). ValueOf () AND (2) Colors: _ (cars) .uniq ('color'). Map ('color' ).Nilai dari(). Anda bisa mematahkan warnanya dan menutupnya. (Semua itu jika Anda mengupgrade de lodash yang digunakan)
Vitor Tyburski

38

Jika Anda ingin menghapus duplikat berdasarkan id, Anda dapat melakukan sesuatu seperti ini:

var res = [
  {id: 1, content: 'heeey'},
  {id: 2, content: 'woah'}, 
  {id: 1, content:'foo'},
  {id: 1, content: 'heeey'},
];
var uniques = _.map(_.groupBy(res,function(doc){
  return doc.id;
}),function(grouped){
  return grouped[0];
});

//uniques
//[{id: 1, content: 'heeey'},{id: 2, content: 'woah'}]

Jawaban yang diterima tidak berfungsi jika pengenal uniknya adalah a Date. Namun demikian.
gunwin

17

Implementasi jawaban Shiplu.

var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];

var x = _.uniq( _.collect( foo, function( x ){
    return JSON.stringify( x );
}));

console.log( x ); // returns [ { "a" : "1" }, { "b" : "2" } ]

btw, bagaimana Anda mendapatkan 4 suara positif? Untuk mendapatkan properti hasil Anda, Anda harus mengembalikan setiap nilai array kembali menjadi objek. Sesuatu seperti JSON.parse(x[0]).akarena x bukanlah array objek, itu adalah array string. Selain itu, jika Anda menambahkan nilai b ke keunikan dan membalik urutan a / b, nilai tersebut tidak lagi dianggap unik oleh fungsi Anda. (mis. `" {\ "a \": \ "1 \", \ "b \": 2} "! =" {\ "b \": 2, \ "a \": \ "1 \"} ") Mungkin saya melewatkan sesuatu, tetapi bukankah seharusnya hasilnya setidaknya berguna? Berikut adalah jsbin untuk menggambarkan jsbin.com/utoruz/2/edit
Shanimal

1
Anda benar, kondisi memiliki kunci yang sama tetapi dalam urutan yang berbeda merusak implementasi. Tapi saya tidak yakin mengapa Anda hanya memeriksa kunci auntuk setiap objek, ketika mungkin ada objek duplikat yang tidak berisi kunci tersebut a. Namun, akan masuk akal jika aitu adalah id unik.
Larry Battle

Ketika saya menjawab pertanyaan itu, bagi saya fokus pertanyaan itu adalah untuk mengesampingkan (a ==(=) b when a = b = {a:1}). Inti dari jawaban saya adalah iterator. Kucoba menjawab tanpa khawatir motifnya, mana bisa apa saja kan? (mis. mungkin mereka ingin mengekstrak daftar merek , warna dari daftar mobil dalam sebuah pertunjukan. jsbin.com/evodub/2/edit ) Cheers!
Shanimal

Juga saya pikir ini membantu kita memberikan jawaban yang ringkas ketika seseorang mengajukan pertanyaan memberikan motif. Ini perlombaan, jadi saya lebih suka menjadi yang pertama dan mengklarifikasi jika perlu. Selamat Hari St Patrick.
Shanimal

Saya baru saja memberikan upvote lain karena ini menjawab pertanyaan saya tentang membandingkan array bersarang. Hanya mencari cara untuk menimpaiterator
nevi_me

15

Ketika saya memiliki id atribut, ini adalah cara favorit saya di garis bawah:

var x = [{i:2}, {i:2, x:42}, {i:4}, {i:3}];
_.chain(x).indexBy("i").values().value();
// > [{i:2, x:42}, {i:4}, {i:3}]

12

Menggunakan garis bawah lib unik berikut bekerja untuk saya, saya membuat daftar unik berdasarkan _id kemudian mengembalikan nilai String _id:

var uniqueEntities = _.uniq(entities, function (item, key, a) {
                                    return item._id.toString();
                                });

10

Berikut adalah solusi sederhana, yang menggunakan perbandingan objek yang dalam untuk memeriksa duplikat (tanpa beralih ke JSON, yang tidak efisien dan hacky)

var newArr = _.filter(oldArr, function (element, index) {
    // tests if the element has a duplicate in the rest of the array
    for(index += 1; index < oldArr.length; index += 1) {
        if (_.isEqual(element, oldArr[index])) {
            return false;
        }
    }
    return true;
});

Ini menyaring semua elemen jika mereka memiliki duplikat nanti dalam array - sehingga elemen duplikat terakhir disimpan.

Pengujian untuk penggunaan duplikat _.isEqualyang melakukan perbandingan mendalam yang dioptimalkan antara dua objek, lihat dokumentasi isEqual garis bawah untuk info selengkapnya.

edit: diperbarui untuk digunakan _.filteryang merupakan pendekatan yang lebih bersih


Tidak bergantung pada memiliki properti unik yang telah ditentukan sebelumnya? Saya suka itu.
Don McCurdy

1
Solusi yang baik untuk larik kecil objek tetapi perulangan dalam satu loop mahal dibandingkan dengan menyediakan id uniq.
penner


7

Coba fungsi iterator

Misalnya Anda dapat mengembalikan elemen pertama

x = [['a',1],['b',2],['a',1]]

_.uniq(x,false,function(i){  

   return i[0]   //'a','b'

})

=> [['a', 1], ['b', 2]]


argumen detik sebenarnya opsional, Anda juga dapat melakukannya_.uniq(x,function(i){ return i[0]; });
jakecraige

3

inilah solusi saya (coffeescript):

_.mixin
  deepUniq: (coll) ->
    result = []
    remove_first_el_duplicates = (coll2) ->

      rest = _.rest(coll2)
      first = _.first(coll2)
      result.push first
      equalsFirst = (el) -> _.isEqual(el,first)

      newColl = _.reject rest, equalsFirst

      unless _.isEmpty newColl
        remove_first_el_duplicates newColl

    remove_first_el_duplicates(coll)
    result

contoh:

_.deepUniq([ {a:1,b:12}, [ 2, 1, 2, 1 ], [ 1, 2, 1, 2 ],[ 2, 1, 2, 1 ], {a:1,b:12} ]) 
//=> [ { a: 1, b: 12 }, [ 2, 1, 2, 1 ], [ 1, 2, 1, 2 ] ]

3

dengan garis bawah saya harus menggunakan String () dalam fungsi iteratee

function isUniq(item) {
    return String(item.user);
}
var myUniqArray = _.uniq(myArray, isUniq);

0

Saya ingin menyelesaikan solusi sederhana ini dengan cara penulisan yang lugas, dengan sedikit beban biaya komputasi ... tetapi bukankah itu solusi yang sepele dengan definisi variabel minimum, bukan?

function uniq(ArrayObjects){
  var out = []
  ArrayObjects.map(obj => {
    if(_.every(out, outobj => !_.isEqual(obj, outobj))) out.push(obj)
  })
  return out
}

0
var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];
var bar = _.map(_.groupBy(foo, function (f) { 
        return JSON.stringify(f); 
    }), function (gr) { 
        return gr[0]; 
    }
);

Mari kita uraikan ini. Pertama mari kelompokkan item array dengan nilai stringnya

var grouped = _.groupBy(foo, function (f) { 
    return JSON.stringify(f); 
});

grouped seperti:

{
    '{ "a" : "1" }' = [ { "a" : "1" } { "a" : "1" } ],
    '{ "b" : "2" }' = [ { "b" : "2" } ]
}

Kemudian mari ambil elemen pertama dari setiap grup

var bar = _.map(grouped, function(gr)
    return gr[0]; 
});

bar seperti: [ { "a" : "1" }, { "b" : "2" } ]

Gabungkan semuanya:

var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];
var bar = _.map(_.groupBy(foo, function (f) { 
        return JSON.stringify(f); 
    }), function (gr) { 
        return gr[0]; 
    }
);

3
Selamat datang di stackoverflow. Selain kode yang Anda berikan, coba berikan penjelasan tentang mengapa dan bagaimana ini memperbaiki masalah.
jtate

panggilan yang bagus. Terima kasih. Diperbarui dengan perincian tentang cara kerjanya.
Kelly Bigley

-5

Anda dapat melakukannya dengan singkat sebagai:

_.uniq(foo, 'a')


solusi Anda tidak berfungsi untuk array objek, tetapi hanya untuk array
Toucouleur
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.