Javascript için Alt Çizgi ile yinelenen nesneleri kaldırma


124

Bu tür bir dizim var:

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

Şunlara sahip olması için filtrelemek istiyorum:

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

_.Uniq kullanmayı denedim ama sanırım { "a" : "1" }kendine eşit olmadığı için çalışmıyor. Geçersiz kılınan eşittir işlevi ile alt çizgi uniq sağlamanın herhangi bir yolu var mı?


Lütfen kodunuzu da gönderin
Chetter Hummin

Böyle şeyler { "a" : "2" }var mı? Eğer öyleyse, onu benzersiz kılan özellik mi yoksa değer mi?
Matt

Evet, anahtar olarak bir özniteliğim var, birinin bana başka bir konuda gösterdiği dizini uyguladım, ancak daha sonra bazı ortak kitaplıkları kullanarak kodumu temizlemek istedim
artı-

1
Lütfen cevabı değiştiriniz.
Vadorequest

Yanıtlar:


232

.uniq / .unique bir geri aramayı kabul eder

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

Notlar:

  1. Karşılaştırma için kullanılan geri arama dönüş değeri
  2. Benzersiz olarak kullanılan benzersiz dönüş değerine sahip ilk karşılaştırma nesnesi
  3. undercorejs.org , geri arama kullanımı olmadığını gösterir
  4. lodash.com kullanımı gösterir

Başka bir örnek: Bir listeden araba markalarını, renkleri çıkarmak için geri aramayı kullanma


falseiçin gerekli değildir _.uniq(). Ayrıca Lodash'ta _.uniq(a, 'a');mülkleri anesnelerin üzerine çekeceği için böyle yazabilirdiniz .
Larry Battle

"'_.Pluck' geri arama kısaltması" yalnızca isSorted için bir değer iletirseniz çalışır (örn. _.uniq(a, false, 'a')) Github / bestiejs / lodash'a ping attım ve sorunun uçta düzeltildiğini söylediler. Bu nedenle, bir işlevi kullanmıyorsanız, en yenisine sahip olduğunuzdan emin olun. Bu, alt çizgi için bir sorun olmayabilir.
Shanimal

2
Yineleyici kulağa iyi bir isim gibi gelmiyor, her nesnenin kimliğini belirleyecek hash benzeri bir işlev
Juan Mendes

Lodash belgelerinde daha tutarlı olması için geri aramayı kullanmak üzere düzenlendi :)
Shanimal

1
Jsbin'deki örneğiniz bir güncellemeye sahip olabilir. (1) Yapar: _ (arabalar) .uniq ('make'). Map ('make']. ValueOf () VE (2) Renkler: _ (arabalar) .uniq ('renk'). Harita ('renk' ).değeri(). Rengi olgunlaştırabilir ve kapanış yapabilirsiniz. (Kullanılan de lodash'ı yükseltirseniz hepsi)
Vitor Tyburski

38

Bir kimliğe göre kopyaları kaldırmak istiyorsanız, aşağıdaki gibi bir şey yapabilirsiniz:

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

Kabul edilen yanıt, benzersiz tanımlayıcı bir Date. Ancak bu yapar.
gunwin

17

Shiplu'nun cevabının uygulanması.

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, nasıl 4 olumlu oy aldınız? Sonucunuzun özelliklerine ulaşmak için her dizi değerini bir nesneye geri döndürmeniz gerekir. Örneğin JSON.parse(x[0]).ax bir nesne dizisi olmadığı için bir dizi dizisidir. Ayrıca, uniquelere b değerleri eklerseniz ve a / b sırasını tersine çevirirseniz, bunlar artık işleviniz tarafından benzersiz olarak kabul edilmez. (örneğin, "{\" a \ ": \" 1 \ ", \" b \ ": 2}"! = "{\" b \ ": 2, \" a \ ": \" 1 \ "} ") Belki bir şeyi kaçırıyorum ama sonuç en azından yararlı olmamalı mı? İşte jsbin.com/utoruz/2/edit'i göstermek için bir jsbin
Shanimal

1
Haklısınız, aynı anahtarlara sahip olmak, ancak farklı sırayla uygulamayı bozuyor. Ancak, anahtarı aiçermeyen yinelenen nesneler olabileceği zaman, neden yalnızca her nesnenin anahtarını kontrol ettiğinizden emin değilim a. Ancak, abenzersiz bir kimlik olsaydı mantıklı olurdu .
Larry Battle

Soruyu cevaplarken, bana sorunun odak noktasının geçersiz kılmak olduğu görüldü (a ==(=) b when a = b = {a:1}). Cevabımın amacı yineleyiciydi. Sebep hakkında endişelenmeden cevap vermeye çalıştım, hangisi herhangi bir şey olabilir, değil mi? (örneğin, belki bir şovdaki araba listesinden bir marka, renk listesi çıkarmak istediler. jsbin.com/evodub/2/edit ) Şerefe!
Shanimal

Ayrıca, bir soru soran biri neden sağladığında kısa cevaplar vermemize yardımcı olduğunu düşünüyorum. Bu bir yarış, bu yüzden ilk olmayı ve gerekirse açıklığa kavuşturmayı tercih ederim. Mutlu Aziz Patrick Günü.
Shanimal

Ben sadece başka bir olumlu oy verdim çünkü bu, iç içe dizileri karşılaştırmayla ilgili sorumu yanıtladı. Sadece nasıl geçersiz iterator
kılınacağını arıyordum

15

Bir öznitelik kimliğim olduğunda, alt çizgide tercih ettiğim yol budur:

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

Aşağıdaki benzersiz lib alt çizgisini kullanmak benim için çalışıyor, listeyi _id temelinde benzersiz yapıyorum ve ardından _id String değerini döndürüyorum:

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

10

İşte kopyaları kontrol etmek için derin bir nesne karşılaştırması kullanan basit bir çözüm (verimsiz ve hacky olan JSON'a dönüştürmeye başvurmadan)

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

Dizide daha sonra bir kopyası varsa, tüm öğeleri filtreler - böylece son yinelenen öğe korunur.

_.isEqualİki nesne arasında optimize edilmiş derin bir karşılaştırma gerçekleştiren yinelenen kullanımlar için test , daha fazla bilgi için alt çizgi isEqual belgelerine bakın.

düzenleme: _.filterdaha temiz bir yaklaşım olan kullanmak için güncellendi


Önceden tanımlanmış benzersiz bir özelliğe sahip olmaya bağlı değil mi? Bunu sevdim.
Don McCurdy

1
Küçük bir nesne dizisi için iyi bir çözüm, ancak döngü içindeki bir döngü, bir benzersiz kimlik sağlamaya kıyasla pahalıdır.
penner


7

Yineleyici işlevini deneyin

Örneğin ilk öğeyi döndürebilirsiniz

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

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

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

})

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


saniye argümanı aslında isteğe bağlıdır, siz de yapabilirsiniz_.uniq(x,function(i){ return i[0]; });
jakecraige

3

İşte benim çözümüm (coffeeescript):

_.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

misal:

_.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

ile çizgi ı kullanmak zorunda String () içinde iteratee işlevi

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

0

Bu basit çözümü basit bir şekilde yazmak istedim, biraz hesaplama masrafları ile çözmek istedim ... ama minimum değişken tanımlı önemsiz bir çözüm değil mi?

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

Bunu parçalayalım. İlk olarak dizi öğelerini dizgeli değerlerine göre gruplayalım

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

grouped şöyle görünüyor:

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

Sonra her gruptan ilk öğeyi alalım

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

bar şöyle görünüyor: [ { "a" : "1" }, { "b" : "2" } ]

Hepsini bir araya getirmek:

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
Stackoverflow'a hoş geldiniz. Sağladığınız koda ek olarak, bunun sorunu neden ve nasıl düzelttiğine dair biraz da açıklama yapmaya çalışın.
jtate

İyi karar. Teşekkürler. Bunun nasıl çalıştığına dair bir döküm ile güncellendi.
Kelly Bigley

-5

Bunu kısaca şu şekilde yapabilirsiniz:

_.uniq(foo, 'a')


çözümünüz nesne dizileri için değil, sadece diziler için çalışıyor
Toucouleur
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.