Bir diziden kopyaları kaldır


100

Şuna benzeyen bir dizi nesnem var:

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"}
    ...
];

Gördüğünüz gibi bazı isimler tekrarlanıyor. Sadece isimleri olan yeni bir dizi almak istiyorum, ancak bazı isimler tekrarlanırsa onu tekrar eklemek istemiyorum. Bu diziyi istiyorum:

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

Bunu şununla yapmaya çalışıyorum map:

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

Ancak sorun şu ki, bunun geri dönüşü:

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

mapZaten var olan bir öğeyi döndürmemesi için içinde bazı koşulları nasıl ayarlayabilirim ? Bunu mapveya başka bir ECMAScript 5 veya ECMAScript 6 özelliği ile yapmak istiyorum .


2
Ardından kopyaları diziden kaldırın.
Tushar



İd: 125 içeren satır neden virgülle bitmiyor?
Peter Mortensen

Dizinin büyük olması durumunda, .indexOf () kullanan tüm yanıtların , ikinci dereceden zaman karmaşıklığı nedeniyle düşük performansa sahip olacağını lütfen unutmayın . Sözlük olarak ES6 Set veya bir ES5 nesnesi kullanmanızı tavsiye ederim .
joeytwiddle

Yanıtlar:


211

ES6 ile, Setyalnızca nesnelerin adlarını eşledikten sonra benzersiz değerler için kullanabilirsiniz .

Bu teklif , öğeleri yeni bir dizide toplamak için bir yayılma sözdizimi... kullanır .

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


9
Bilgilerim için .. ne yapar ...?
Rajshekar Reddy

9
@RajshekarReddy, yinelenebilir bir nesne ile bir dizi oluşturmak için yayılmış bir sözdizimidir... .
Nina Scholz

5
Ben "Set" in kendisine oy vermiyorum, daha ziyade spread operatörünün akıllıca kullanımı için. Yeni bir şey öğrenmek veya yeni bir şeyin pratik bir örneğe uygulandığını görmek her zaman güzeldir, bu yüzden bu gönderi bir oylamayı hak ediyor.
briosheje

34
Bu sadece benim kişisel görüşüm, ama oldukça yaygın bir görüş . Kullanımı Array.from, dönüşümün amacını çok daha iyi iletir (ve ayrıca yeni başlayanları anlamak / aramak daha kolaydır), yayılma sözdizimi yalnızca yayılmış öğeden biri olduğunda kullanılmalıdır. Belki buna "kötü uygulama" demek biraz fazla serttir, üzgünüm, umarım yaygın bir deyim haline gelmesini önlemeyi umuyorum.
Bergi

3
@KRyan ES6 çok yeni mi? 2015 Haziran ayında tamamlanmıştır. Yeni özellikleri anlamanın ve kullanmaya başlamanın zamanı geldi
edc65

64

ES 6 (Setsiz) olmayan bir JavaScript çözümü arıyorsanız, Array reduceyöntemini kullanabilirsiniz :

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


2
Bu cevabın ayrıca, ara diziler veya kümeler gerektirmemesi, özellikle de sadece isimleri içerenler gibi bir yararı vardır. (Doğrudan nesneler dizisinden nesne dizisine gider.) +1
jpmc26

@Iwrestledabearonce, bu ikinci parametre döndürülenle aynı nesne değil mi?
Kaiido

Evet, ama birinden diğerine sıralama veya filtre gibi doğrudan gitmiyor, boş bir diziden yeniden oluşturuldu.
Bir ayıyla güreştim.

1
@Dekel - Daha küçük sürüm :)var names = array.reduce(function(a, b) { a.indexOf(b.name) === -1 && a.push(b.name) return a; }, []);
Rayon

3
@Rayon Lütfen kaynak kodun boyutuna çok fazla dikkat etmeyin, bu birçok kendi kendine programcı için ortak bir tuzaktır, en önemlisi programınız verimli ve okunabilir olmalıdır.
yaprak

16

Şahsen ben neden herkesin ES 6'dan hoşlandığını anlamıyorum. Bu benim kodum olsaydı, olabildiğince çok tarayıcıyı desteklemeyi tercih ederdim.

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


2
Her indexOfzaman -ing yerine bir nesneyi sözlük olarak kullanmak daha performanslı olmaz mı? Örneğin yap added[name] = trueve if(added[name])yerine if(a.indexOf(name)).
Bojidar Marinov

7
"şahsen neden herkesin es6'dan hoşlandığını anlamıyorum" neden a ile kur yapıyorsunuz goto fail, indeks değişkeninizi kapsama alanına sızdırıyorsunuz vb. vb. ES6 iyi nedenlerle standarda kodlanmıştır ve çoğu için eski tarayıcılar için çok kolay doldurma / dönüştürme kısmen kolaydır.
Jared Smith

5
Daha okunaklı mı? Öğeleri bir diziye iten garip bir döngüdür. Bundan daha okunaklı olamaz ......
Bir ayıyla güreştim.

4
Dürüst olmak gerekirse, şikayet edecek bir şey bulmak için çok uğraşıyormuşsun gibi geliyor.
Bir ayıyla güreştim.

2
"Ünlü Apple SSL hatasından bahsediyorum" - Bağlam dışında rastgele yorumlarla gidip ona atıfta bulunmanız ve insanların onu tanımasını beklemeniz o kadar ünlü değil.
Hejazzman

14

Ayrıca sadece birleştirmek olabilir mapilefilter

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)


11

Belirli bir nesnenin kendi numaralandırılabilir özellik adlarının dizisini Array.prototype.reduce () ile değişken yinelemenin nesne sonucundan almak için Object.keys () öğesini kullanabilirsiniz ; burada anahtarlar yok edilmiş adlardırarray

Kod:

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)


7

Burada birçok iyi cevap var. Size başka bir bakış açısı kazandırmak umuduyla biraz çeşitlilikle katkıda bulunmak istiyorum.

Diziler JavaScript'te nesne türündedir, bu nedenle aynı anda karma olarak kullanılabilirler. Bu işlevselliği kullanarak, O (n) zaman karmaşıklığına sahip tek bir azaltma işleminde yapılacak işi büyük ölçüde basitleştirebiliriz.

Dizinizin dizi anahtarları dışında bazı özellikleri tutmasından memnun değilseniz, ayrı bir hash nesnesi tutmayı da düşünebilirsiniz.

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


Bu ES5 çözümü iyi bir performansa sahiptir, ancak diziyi iki amaç için kullanmak kafa karıştırıcıdır ve isimlerden biri yalnızca bir sayı ise tehlikelidir. İşleri p[c.name]ayrı bir nesne üzerinde yapmayı ove daha sonra atmanızı tavsiye ederim .
joeytwiddle

7

Sadece namedeğerlere ihtiyacınız varsa , Setgidilecek yolun a olduğuna katılıyorum .

Bununla birlikte , namemülke dayalı olarak bir dizi benzersiz nesne almak istiyorsanız , bir Map. Harita oluşturmanın hızlı bir yolu, bir dizi dizidir [key, value]:

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

Bunun ek bir avantajı , kaynak nesnelerle bağlantıyı kaybetmeden, benzersiz olmayanları kesen işlevselliğe Mapsahip olmanızdır filter. Elbette, yalnızca benzersiz nesne kümesine birden çok kez başvurmanız gerektiğinde gereklidir.



2

ES6 ile bu işi yapmalı.

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


11
mapyan etkileri olmaması için saf işlevlerle kullanılması gerekiyordu. Bu forEachveya için bir iş olurdu reduce.
Vincent van der Weele

1

Underscore JS kullanarak,

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>

'


0

ES5'te, O ( n ) performansı için sözlük olarak bir nesne kullanın .

Bu yalnızca tüm anahtarlar Dizeler ise çalışır.

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

İsterseniz aynı şeyi tek bir ifadede de yapabilirsiniz:

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

ancak emir kipini okumayı daha kolay buluyorum.


Açıklık için ES6 ok işlevlerini kullandım. Bir aktarıcı olmadan gerçekten ES5'i hedefliyorsanız, bunun yerine tam formu kullanmanız gerekecektir:function (item) { return item.name; }
joeytwiddle

Alternatif olarak Object.keys(), bu cevap kullanımları filter()henüz oldukça şık haritasında, saklanan henüz sadece bu isimleri tutmak.
joeytwiddle


0

Kullanım array#forEach()ve array#indexOf()isterseniz böyle yöntemler maksimum uyumluluk henüz özlü söz dizimi:

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

Ancak, uyumluluk ise, söz konusu değildir kullanımı 6 ECMAscript 'in Setamacı, array#mapve Array.from()bu gibi yöntemler:

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


0

Ayrı bir boş dizi kullanarak bunu böyle yaptım.

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)	


-1

1 astar arayanlar için

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

veya dizinin prototipinde yöntemler kullanmadan

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

bununla başa çıkmak için bazı saf işlevler yazmak için yararlı olabilir

const get_uniq_values = (key, arr) => reduce(arr, (a, o) => includes(a, o[key]) ? a : [o[key], ...a], []);

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

11
Bu kadar çok alt çizgi kullanmak için özel bir nedeniniz var mı?
Nina Scholz
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.