JavaScript'teki bir nesne dizisinden yinelenenleri kaldırma


373

Bir dizi nesne içeren bir nesne 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"});

Bir diziden yinelenen nesneleri kaldırmak için en iyi yöntem nedir merak ediyorum. Yani, örneğin, şeyler. Her şey ...

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

Bir diziye aynı parametrelerin eklenmesiyle hashtable / object'i nasıl durduracağınız anlamına mı geliyor?
Matthew Lock

1
Mathew -> Yinelenen bir nesnenin diziye ilk etapta eklenmesini önlemek daha basitse, daha sonra filtrelemek yerine, evet, bu da iyi olur.
Travis

2
İnsanların değişkenlerini nasıl adlandırdığı beni şaşırtmaya devam ediyor. Bazen gerçekten gereksiz yere karmaşık hale getirmek istediklerini düşünüyorum. Next to see will aaaaa.aaaa.push(...):)
dazito

Yanıtlar:


154

İlkel bir yöntem:

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 döngüsünde uzunluğu asla kullanmamalısınız, çünkü her yinelemede hesaplanan her şeyi yavaşlatır. Bunu döngü dışındaki bir değişkene atayın ve değişkeni things.thing.length yerine iletin.
0v3rth3d4wn

12
@aefxx Bu işlevi tam olarak anlamıyorum, "yer" aynı fakat adın farklı olduğu durumu nasıl ele alıyorsunuz?
Kuan

2
Bu işe yarıyor olsa da, anahtarları almak asla garanti edilmediğinden sıralı bir diziyle ilgilenmez. Böylece, tekrar sıralıyorsunuz. Şimdi, dizinin sıralanmadığını, ancak sırasının önemli olduğunu varsayalım, siparişin sağlam kaldığından emin olmanın bir yolu yok
Deepak GM

1
@DeepakGM Kesinlikle haklısın. Cevap, belirli bir emri (zorunlu olarak) korumaz. Bu bir gereklilikse, kişi başka bir çözüm aramalıdır.
aefxx

X içeren ve dizisi kaldırılmış bir dizideki nesneleri kaldırmak için yukarıdakileri nasıl değiştirebilirim?
Ryan Holton

435

Biraz es6sihire ne dersin ?

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

Referans URL

Daha genel bir çözüm:

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

Stackblitz Örneği


81
Bu kısaltılabilir:things.thing = things.thing.filter((thing, index, self) => self.findIndex(t => t.place === thing.place && t.name === thing.name) === index)
Josh Cole

Mükemmel çalışıyor! var uniqueArrayOfObjects = arrayOfObjects.filter (function (obj, index, self) {dönüş dizini === self.findIndex (function (t) {return t ['obj-property'] === obj ['obj-property'] });}); Uygun JS sözdizimini kullandığınızdan emin olun.
Mohamed Salem Lamiri

Bunlar uygun JS sözdizimidir. Sizinki 1) yağ ok işlevleri 2) örtük dönüş veya 3) nokta gösterimi kullanmıyor. Seninki ES5 sözdizimidir. Diğerleri çoğunlukla ES6'dır (ECMA2015). Hepsi 2017'de geçerlidir. Bkz. Jaredwilli'nin yorumu.
agm1984

8
@vsync sadece BKM'nin cevabını alın ve bir araya getirin, genel bir çözüm şöyle olurdu: const uniqueArray = arrayOfObjects.filter((object,index) => index === arrayOfObjects.findIndex(obj => JSON.stringify(obj) === JSON.stringify(object))); jsfiddle.net/x9ku0p7L/28
Eydrian

9
Buradaki anahtar, findIndex () yönteminin ilk öğenin dizinini döndürmesidir , bu nedenle eşleşen ikinci bir öğe varsa, filtre sırasında asla bulunamaz ve eklenmez. Bir dakika bakıyordum :)
JBaczuk

111

Alt çizgi veya lodash gibi Javascript kütüphanelerini kullanabiliyorsanız _.uniq, kütüphanelerinde fonksiyona bakmanızı tavsiye ederim . Gönderen lodash:

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

Temel olarak, burada bir nesne değişmezi olan diziyi geçirirsiniz ve orijinal veri dizisinde yinelenenleri kaldırmak istediğiniz özniteliği geçirirsiniz, örneğin:

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

GÜNCELLEME : Lodash şimdi bir de tanıttı .uniqBy.


3
@Praveen Pds: Kod örneğinde alt çizgi hakkında bir şey söyledim mi? Dedim ki 'lodash' bu işleve sahip ve alt çizgi benzer. Oy vermeden önce lütfen cevapları dikkatle okuyun.
ambodi

// _underscore.js holdingObject = _.uniq (holdingObject, function (item, key, name) {return item.name;}) kullanarak benzersiz nesneleri listeler.
praveenpds

26
Not: şimdi , örneğin ... belgeleri uniqByyerine kullanmanız gerekir : lodash.com/docs#uniqByuniq_.uniqBy(data, 'name')
drmrbrewer

82

Tek bir alanda yinelenenlere dayalı bir dizide yinelenen nesneleri kaldırmak için bu aynı gereksinimi vardı. Kodu burada buldum: Javascript: Nesneler dizisinden yinelenenleri kaldırın

Yani benim örneğimde, yinelenen licenseNum dize değeri olan diziden herhangi bir nesneyi kaldırıyorum.

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

Sonuçlar:

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
İşlev 'falsy' nesnelerini de filtreleyebiliyorsa, bu daha yararlı olacaktır. for(var i in array) { if(array[i][prop]){ //valid lookupObject[array[i][prop]] = array[i]; } else { console.log('falsy object'); } }
Abdul Sadik Yalcin

Neden aşağıdakileri kullanarak karmaşıklığı 0 (n) for (let i in originalArray) { if (lookupObject[originalArray[i]['id']] === undefined) { newArray.push(originalArray[i]); } lookupObject[originalArray[i]['id']] = originalArray[i]; }
Tudor B.

bu en iyi yoldur çünkü çoğaltılmak istememenizin ne olduğunu bilmek önemlidir. Şimdi bu e6 standartları için redüktör ile yapılabilir mi?
Christian Matthew

69

ES6 + için en kısa bir astar

idBir dizide benzersiz olanları bulun .

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

Birden çok özelliğe ( placeve name) göre benzersiz

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

Tüm özelliklere göre benzersiz (Büyük diziler için yavaş olacaktır)

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

Son olayı sakla.

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

2
Büyü, bu gerçek cevap
Luis Contreras

48

Set kullanarak bir astar

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)

Açıklama:

  1. new Set(myData.map(JSON.stringify))stringize myData öğelerini kullanarak bir Set nesnesi oluşturur .
  2. Set nesnesi her öğenin benzersiz olmasını sağlar.
  3. Sonra Array.from kullanarak oluşturulan kümenin öğelerine dayalı bir dizi oluşturun.
  4. Son olarak, dize öğeyi bir nesneye dönüştürmek için JSON.parse kullanın.

18
sorun {a: 1, b: 2}, {b: 2, a: 1} 'e eşit olmayacak
PirateApp

2
Tarih özellikleri ile ilgili bir sorun olacağını unutmayın
MarkosyanArtur

Bu satır, orijinal nesne dizisinde bulunmayan bir satır nesnesiyle rastgele null değerler oluşturur. Yardım edebilir misin lütfen?
B1K

46

Kullanılması ES6 + tek bir satırda size anahtar ile nesnelerin benzersiz bir listesini alabilirsiniz:

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

Bir fonksiyona konabilir:

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

İşte çalışan bir örnek:

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

O nasıl çalışır

İlk olarak dizi, Harita için girdi olarak kullanılabilecek şekilde yeniden eşleştirilir .

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

yani dizinin her bir öğesi 2 elemanlı başka bir diziye dönüştürülecektir; Seçilen tuş ilk elemanı ve benzeri gibi tüm başlangıç ürünün , ikinci eleman olarak, bu giriş (örn., adı dizi girişleri , harita girişleri ). Ve burada Harita yapıcısına dizi girişlerinin nasıl ekleneceğini gösteren bir örnek olan resmi doküman .

Anahtar yerleştirildiğinde örnek :

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

İkincisi, bu değiştirilmiş diziyi Harita yapıcısına geçiriyoruz ve işte sihir oluyor. Harita, aynı anahtarın yalnızca son girilen değerini koruyarak yinelenen anahtar değerlerini ortadan kaldırır. Not : Harita ekleme sırasını korur. ( Harita ve nesne arasındaki farkı kontrol edin )

yeni Harita (giriş haritası yukarıda eşleştirildi)

Üçüncüsü, orijinal değerleri almak için harita değerlerini kullanıyoruz, ancak bu sefer kopyalar olmadan.

yeni Harita (mappedArr). değerler ()

Ve sonuncusu, bu değerleri yeni bir diziye eklemek, böylece ilk yapı olarak görünecek ve geri dönecektir:

dönüş [... yeni Harita (mappedArr) .values ​​()]


Bu, orijinal soruyu cevaplamaz, çünkü bu bir id. Soru tüm nesnenin placevename
L. Holanda

ES6 işleviniz çok kısa ve pratik görünüyor. Biraz daha açıklayabilir misiniz? Tam olarak ne oluyor? İlk veya son kopyalar kaldırıldı mı? Yoksa rasgele mi, hangisi kaldırılıyor? Bu yardımcı olur, teşekkürler.
David Schumann

Anlayabildiğim kadarıyla, anahtar olarak özellik değeri olan bir Harita oluşturulur. Ancak, dizinin sırasının nasıl korunduğu veya korunduğu% 100 değildir.
David Schumann

1
Merhaba @ DavidSchumann, cevabı güncelleyeceğim ve nasıl çalıştığını açıklayacağım. Ancak kısa cevap için sipariş korunur ve ilki kaldırılır ... Sadece haritaya nasıl eklendiğini düşünün ... anahtarın zaten var olup olmadığını kontrol eder, sonuncusu kalır
V Sambor

30

Bir nesnenin yalnızca bir alanıyla karşılaştırmaya ihtiyacınız varsa Array yineleme yöntemlerini kullanarak bunu yapmak için başka bir seçenek vardır:

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

Bu O (n²) 'den daha büyük bir sıraya sahip olmasına rağmen, bu benim kullanım durumuma uyar çünkü dizi boyutum her zaman 30'dan az olacaktır.
Sterex

24

bir astar burada

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
Sadece tek bir yinelenen değeri olan nesneleri kaldırmak istiyorsanız, tamamen çoğaltılmış nesneler için çok temiz değil, güzel ve temiz.
David Barker

22

Tüm eklemelerden sonraya kadar yinelenenleri kaldırmak için bekleyebilirseniz, tipik yaklaşım önce diziyi sıralamak ve daha sonra yinelenenleri ortadan kaldırmaktır. Sıralama, ilerlerken her öğe için dizi taramanın N * N yaklaşımını önler.

"Yinelemeleri yok et" işlevi genellikle benzersiz veya benzersiz olarak adlandırılır . Mevcut bazı uygulamalar iki adımı birleştirebilir, örneğin, prototipin benzersiz

Bu yayının kütüphanenizde yoksa denemek için birkaç fikri var (ve kaçınmak için :-)) ! Şahsen bunu en doğru şekilde buluyorum:

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

Bu, doğal sıralama düzeni olmadan genel nesneler için çalışmaz.
Tim Down

Doğru, kullanıcı tarafından sağlanan bir karşılaştırma sürümü ekledim.
maccullt

Kullanıcı tarafından sağlanan karşılaştırma sürümünüz çalışmaz, çünkü karşılaştırma işleviniz function(_a,_b){return _a.a===_b.a && _a.b===_b.b;}öyleyse dizi sıralanmaz.
graham.reeds

1
Bu geçersiz bir karşılaştırma işlevidir. Gönderen developer.mozilla.org/en/Core_JavaScript_1.5_Reference/... karşılaştırmak ... fonksiyonunun (a, b) {if (daha az bazı sipariş kriter ile b daha) geri dönüş -1; (sipariş kriteri tarafından a, b'den büyükse) 1; // a, b dönüşü 0'a eşit olmalıdır; } ...
maccullt

22

En basit yol kullanmaktır 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
Çözümünüzün neden çalışması gerektiğine, özellikle de sizin yanıtınızın diğer yanıtlardan daha iyi olduğuna dair bir açıklama eklemek Yığın Taşması konusunda iyi bir uygulamadır. Daha fazla bilgi için Nasıl Yanıtlanır bölümünü okuyun .
Samuel Liew

Bu, orijinal soruyu cevaplamaz, çünkü bu bir id. Soru, nesnenin tamamının placevename
L. Holanda

16

Bu, bunu yapmanın genel bir yoludur: bir dizinin iki öğesinin eşit kabul edilip edilmediğini test eden bir işlev iletirsiniz. Bu durumda, karşılaştırılan iki nesnenin nameve placeözelliklerinin değerlerini karşılaştırır.

ES5 yanıtı

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

Orijinal ES3 yanıtı

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
İki nesne, aynı özellikleri ve değerleri paylaşsalar bile eşit olarak değerlendirilmez.
kennebec

Evet biliyorum. Ama açıkçası, soruyu doğru bir şekilde okuyamadım: Bunun, ayıklaması gereken özdeş özelliklere sahip nesneler olduğunu fark etmemiştim. Cevabımı düzenleyeceğim.
Tim Down

1
yerine dizi üyelerinden biri koşulla eşleşen eğer iç arrayContains- gerçek Array.prototype..some yöntem İade kullanırken ait
MarkosyanArtur

13

Listeye bir tane daha eklemek için. ES6 ve Array.reduceile kullanma Array.find.
Bu örnekte, bir guidözelliğe dayalı nesneleri filtreleme .

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

Bir mülk seçimine izin vermek ve tek bir astarda sıkıştırmak için bunu genişletmek:

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

Kullanmak için bir dizi nesne ve deuptan çıkarmak istediğiniz anahtarın adını dize değeri olarak iletin:

const result = uniqify(myArrayOfObjects, 'guid')

11

Ayrıca aşağıdakileri de kullanabilirsiniz Map:

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

Tam örnek:

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

Sonuç:

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

+1, güzel tho biraz daha dedup iç çalışma açıklamakBu şeyler iyi olurdu - şimdi anlıyorum parlak tarafında azaltmak: D
MimiEAM

11

Dang, çocuklar, hadi bu şeyi ezelim, neden biz?

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


Bu, orijinal soruyu cevaplamaz, çünkü bu bir id. Soru tüm nesnenin placevename
L. Holanda

Bu, sorunun yukarıda genelleştirilmesinin iyileştirilmesidir. Orijinal soru 9 yıl önce gönderildi, bu yüzden orijinal poster muhtemelen endişelenmiyor placeve namebugün. Bu konuyu okuyan herkes, bir nesne listesini çıkarmak için en uygun yolu arar ve bu, bunu yapmanın kompakt bir yoludur.
Cliff Hall

11

Bir TypeScript çözümü

Bu, yinelenen nesneleri kaldıracak ve nesne türlerini koruyacaktır.

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

2
bu harika ve kısa!
mojjj

Ve süper yavaş da ...
L. Holanda

7

Düşünen 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 }]

Mükemmel ! Teşekkür ederim ;-)
DonFabiolas

1
Ne lodash'ın uniq'i ne de uniqBy hile yaptı, ama çözümünüz yaptı. Teşekkürler! Doğrudan bir kopya ise, lütfen kodunuzun kaynağını belirtin. lodash.com/docs/4.17.10#uniqWith
Manu CJ

5

Başka bir seçenek, her bir nesne için seçtiğiniz özelliğin değerlerini karşılaştıran ve bunu bir azaltma işlevinde saran özel bir indexOf işlevi oluşturmak olacaktır.

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

Bu benim için harika çalıştı - Ben benzersiz dizi filtreleme gerçekleştirmek için hafif bir nesne karşılaştırıcı olarak lodash.isequalnpm paketi ile eşleştirilmiş ... örneğin nesnelerin farklı dizi. if (_.isEqual(a[i], b)) {Tek bir mülke bakmak yerine sadece takas edildi
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 ve kullanarak tek astar new Map().

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

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

Detaylar: -

  1. Amaçlı .map()Veri listede ve içine her bir nesne dönüştürme [key, value]çift kümesi (uzunluk = 2), birinci eleman (anahtar) olacaktır stringifiednesne ve ikinci (değer) versiyonu, olacağınıobject kendisi.
  2. Yukarıda oluşturulan dizi listesinin new Map()anahtar olarak stringifiednesneye sahip olması ve aynı anahtar eklemesinin mevcut anahtarın geçersiz kılınmasına neden olur.
  3. Kullanıldığında .values()MapIterator öğesine bir Haritadaki tüm değerlerle (obj bizim durumumuzda)
  4. Son olarak, spread ...operatör yukarıdaki adımdaki değerlerle yeni Dizi vermek için.

4

İşte es6 için sadece son öğeyi saklamak istediğiniz bir çözüm. Bu çözüm işlevsel ve Airbnb tarzı ile uyumludur.

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

Yinelenenleri kaldırabilir ve ayrıca tüm yinelenenleri bu kodla kaldırabilirsiniz. Güzel
sg28

4

removeDuplicates () bir nesne dizisini alır ve yinelenen nesneler olmadan yeni bir dizi döndürür (id özelliğine dayalı olarak).

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

Beklenen sonuç:

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

İlk olarak, uniq değişkeninin değerini boş bir nesneye ayarladık.

Ardından, nesneler dizisine filtre uygularız. Filtre, sağlanan işlev tarafından uygulanan sınamayı geçen tüm öğeleri içeren yeni bir dizi oluşturur.

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

Yukarıda, && 'nın kısa devre işlevselliğini kullanıyoruz. && öğesinin sol tarafı true olarak değerlendirilirse, && öğesinin sağındaki değeri döndürür. Sol taraf yanlışsa, && öğesinin sol tarafındaki şeyi döndürür.

Her nesne (obj) için uniq'i obj.id değeri adlı bir özellik için kontrol ederiz (Bu durumda, ilk yinelemede '1' özelliğini kontrol eder.) Döndürdüğünün tersini istiyoruz (ya doğru veya false) bu yüzden! ! uniq [obj.id] içinde. Uniq zaten id özelliğine sahipse, filtre işlevine bu objeyi eklememesini söyleyen false (!) Olarak değerlendirilen true değerini döndürür. Ancak, obj.id özelliğini bulamazsa, false değerini döndürür ve sonra true (!) Olarak değerlendirir ve her şeyi && veya (uniq [obj.id] = true) değerinin sağına döndürür. Bu, true değerini, filtre yöntemine döndürülen diziye eklemesini söyler ve ayrıca {1: true} özelliğini uniq'e ekler. Bu, aynı kimliğe sahip başka herhangi bir obj örneğinin tekrar eklenmeyeceğini garanti eder.


Belki kodunuzu ve soruyu nasıl cevapladığını açıklayınız?
mix3d

Teşekkürler, mix3d. Açıklama ekledim.
MarkN

Bunu açıkladığınız için teşekkürler! Bu çözüm benim için çalışıyor ve burada neler olduğunu anlamadım, ancak burada yayınlanan bir çift benzer :)
Tim Molloy

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

9
Gelecekte ziyaretçilerin ne yaptığını anlayabilmeleri için lütfen kodunuza bir açıklama ekleyin. Teşekkürler.
Bugs

Cevabınız harici bir kod kütüphanesine bağlı ...
Taylor A. Leach

3

Ben bir kombinasyonunu inanmak reduceile JSON.stringifykarşı mükemmel karşılaştırmak Nesneler ve seçici akümülatör zaten olmayanlar ekleyerek zarif bir yoludur.

JSON.stringifyDizinin çok sayıda Nesnesi olduğu ve karmaşık oldukları aşırı durumlarda bir performans sorunu haline gelebileceğini unutmayın , ancak çoğu zaman için bu IMHO'ya gitmenin en kısa yoludur.

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)

Aynı yazmanın başka bir yolu (ancak daha az verimli):

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

benim için çalışan! teşekkür ederim!
javascript110899

2

Ayarı: Nesnelerin diziden çiftleri kaldırma ES6 yollarını Sürekli thisArgbir argüman Array.prototype.filteriçin new Setiyi bir alternatif sağlar:

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

Ancak, sözcüksel kapsamlarına bağlı () =>olarak this, ok işlevleriyle çalışmaz .


2

bir satırda es6 büyüsü ... okunabilir!

// 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 'azaltma' ve 'bulma' dizi yardımcı yöntemleri ile basit çözüm

Verimli ve mükemmel çalışır!

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

Bu bana çok yardımcı oldu, teşekkür ederim
jpisty

1

Eşsiz dizinizin daha sonra sıralanmasının sakıncası yoksa, bu etkili bir çözüm olacaktır:

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

Bu şekilde, geçerli öğeyi yalnızca dizideki önceki öğeyle karşılaştırmanız gerekir. Filtering ( O(n*log(n))) yönteminden önce bir kez sıralama , her dizi öğesi ( O(n²)) için dizinin tamamında bir kopya aramaktan daha ucuzdur .


1

Bu, nesne dizisinden yinelenmenin nasıl kaldırılacağının basit bir yoludur.

Verilerle çok çalışıyorum ve bu benim için yararlı.

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

konsola yazdırılacak:

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

Bu çözüm, statik diziden yinelenmeyi kaldırmak için tasarlanmıştır, ancak u arka uçtan veri dizisine veri aktardığınızda, değiştirmeyi kullanmayı düşünün. Çünkü bu durumda veri dizisine itilen yeni değer kaldırılacak ve "eski" değer yine de veri dizisinde saklanacaktır.
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 bir nesne dizisidir. Aynı değere sahip nesneler vardır (burada küçük bir örnek, 2 ile aynı item_id değerine sahip iki nesne vardır). check (id) , aynı item_id değerine sahip herhangi bir nesnenin var olup olmadığını kontrol eden bir fonksiyondur. eğer varsa false döndürür aksi takdirde true döndürür. Bu sonuca göre, yeni bir diziye nesne itme obj Yukarıdaki kod verilir [{"item_id":1},{"item_id":2}]


Biraz açıklama ekle
Mathews Sunny

@Billa İyi mi?
Bibin Jaimon

1

Lodash kütüphanesini duydun mu? Gerçekten, mantığınızı koda uygulamak istemediğinizde ve optimize edilmiş ve güvenilir olan zaten mevcut olan kodu kullandığınızda bu yardımcı programı öneririm.

Bunun gibi bir dizi oluşturmayı düşünün

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

Bir özniteliği benzersiz tutmak istiyorsanız, bunu lodash kütüphanesini kullanarak çok iyi yapabileceğinizi unutmayın. Burada _.uniqBy kullanabilirsiniz

.uniqBy (dizi, [yineleme = .identity])

Bu yöntem _.uniq gibidir bu kriter oluşturmak için dizideki her bir eleman için çağrılır iteratee kabul dışında (her bir elemanın, sadece ilk geçtiği muhafaza edildiği bir dizi, bir çift serbest versiyonu verir) hangi teklik hesaplanır.

Örneğin, benzersiz "yer" özelliğine sahip bir dizi döndürmek istiyorsanız

_.uniqBy (işler, her şey, 'yer')

Benzer şekilde, 'ad' olarak benzersiz bir özellik istiyorsanız

_.uniqBy (işler, her şey, 'ad')

Bu yardımcı olur umarım.

Şerefe!

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.