SORU
10 ŞUBAT 2012, Cuma


JavaScript Dizi Çiftleri çıkarın

Bu böyle basit bir ihtiyaç gibi görünüyor ama zaman bir aşırı miktarda boşuna bunu yapmak için harcadım. BÖYLECE diğer sorulara baktım ve istediğimi bulamadım. Olabilir ya da çiftleri içeremez peoplenames = new Array("Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"); gibi çok basit bir JavaScript dizi var ve sadece çiftleri kaldırmak ve yeni bir dizi benzersiz değerleri koymak istiyorum. İşte bu kadar. Denedim bütün kodları var ama işe yaramıyorlar çünkü gereksiz olduğunu düşünüyorum. Biri bunu yapmış ve bana yardımcı olabilir Eğer gerçekten takdir ediyorum. JavaScript veya jQuery çözümleri de kabul edilebilir.

İlgili: Easiest way to find duplicate values in a JavaScript array

CEVAP
10 ŞUBAT 2012, Cuma


"Akıllı" ama saf bir şekilde

uniqueArray = a.filter(function(item, pos) {
    return a.indexOf(item) == pos;
})

Temelde, biz dizi üzerinde yineleme ve her öğe için, eğer dizideki bu elemanı ilk konuma geçerli konumu eşit olup olmadığını kontrol edin. Belli ki, bu iki pozisyon öğeleri çoğaltmak için farklıdır.

3 ("Bu dizi") filtre parametre bir dizi değişken bir kapatma engelleyebiliriz geri: kullanılması

uniqueArray = a.filter(function(item, pos, self) {
    return self.indexOf(item) == pos;
})

Kısa olsa da bu algoritma büyük diziler için özellikle etkili bir yöntem değildir (kuadratik zaman).

Kurtarmaya Hashtables

function uniq(a) {
    var seen = {};
    return a.filter(function(item) {
        return seen.hasOwnProperty(item) ? false : (seen[item] = true);
    });
}

Bu genellikle yapılır. Fikri bir karma tablo, her öğe yerleştirin ve varlığını anında kontrol edin. Bu bizim doğrusal zaman verir, ama en az iki dezavantajları vardır:

  • karma tuşlar sadece Javascript dizeleri olabilir bu yana, bu kod numaraları ayrım yapmıyor ve "sayısal bir dize". Sadece [1] döner, uniq([1,"1"])
  • aynı nedenle, tüm nesneleri eşit olarak kabul edilecektir: uniq([{foo:1},{foo:2}]) [{foo:1}] dönecektir.

Bu diziler sadece temel öğeler içerir ve türleri her zaman sayılar (örn umurunda değil varsa, bu en uygun çözüm olduğunu söyledi.

İki dünyanın en iyisi

Evrensel bir çözüm her iki yaklaşım birleştirir: temel öğeler ve nesneler için doğrusal arama için karma aramaları kullanır.

function uniq(a) {
    var prims = {"boolean":{}, "number":{}, "string":{}}, objs = [];

    return a.filter(function(item) {
        var type = typeof item;
        if(type in prims)
            return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true);
        else
            return objs.indexOf(item) >= 0 ? false : objs.push(item);
    });
}

| özgün tür

Başka bir seçenek dizisinin ilk tür, ve her öğe öncekiyle eşit kaldırın

function uniq(a) {
    return a.sort().filter(function(item, pos, ary) {
        return !pos || item != ary[pos - 1];
    })
}

Yine, bu karşılaştırma özel bir işlevi sağlanabilir sürece nesneleri tüm nesneler sort eşit olduğundan () ile işe yaramaz. Ayrıca, bu yöntem, sessizce yan etki olarak orijinal dizi değişiklikler - iyi değil! Eğer giriş zaten sıralanmış ise, bu gitmek için yol (sadece yukarıdan sort kaldırın).

Eşsiz...

Bazen bir liste bazı kriterler sadece eşitlik dışında dayalı uniquify için, örneğin, farklı, ama bazı özellikleri paylaşan nesneler filtrelemek için istenen. Bu zarif bir geri arama geçirerek yapılabilir. Bu" geri her öğe için uygulanır ve eşit elemanları "anahtarları" kaldırılır. "anahtar key bir ilkel dönmek için bekleniyor beri, karma tablo burada iyi çalışır:

function uniqBy(a, key) {
    var seen = {};
    return a.filter(function(item) {
        var k = key(item);
        return seen.hasOwnProperty(k) ? false : (seen[k] = true);
    })
}

Özellikle yararlı key() fiziksel olarak farklı nesneleri kaldırır JSON.stringify ama "bak" aynı:

a = [[1,2,3], [4,5,6], [1,2,3]]
b = uniqBy(a, JSON.stringify)
console.log(b) // [[1,2,3], [4,5,6]]

Kitaplıkları

underscore Lo-Dash hem uniq yöntem sağlar. Kendi algoritmaları ve bu aşağı kaynatın yukarıda: ilk parçacığı için temelde benzer

var result = [];
a.forEach(function(item) {
     if(result.indexOf(item) < 0) {
         result.push(item);
     }
});

Bu ikinci dereceden, ama güzel bir ek güzellikler, sarma yerli ** 33, bir anahtar tarafından uniqify becerisi (kendi dilindeiteratee), ve zaten sıralanmış diziler için en iyi duruma getirme.

Eğer daha önce bir dolar olmadan hiçbir şey duramaz jQuery kullanıyorsanız, şöyle bir şey:

  $.uniqArray = function(a) {
        return $.grep(a, function(item, pos) {
            return $.inArray(item, a) === pos;
        });
  }

yine, ilk parçacığın bir değişiklik.

Performans

İşlev çağrıları Javascript pahalı, bu nedenle yukarıdaki çözümleri, onlar kadar özlü, özellikle verimli değildir. Maksimum performans için, bir döngü ile filter değiştirin ve diğer işlev çağrıları kurtulmak:

function uniq_fast(a) {
    var seen = {};
    var out = [];
    var len = a.length;
    var j = 0;
    for(var i = 0; i < len; i  ) {
         var item = a[i];
         if(seen[item] !== 1) {
               seen[item] = 1;
               out[j  ] = item;
         }
    }
    return out;
}

Çirkin bu kod grubunu #3 yukarıda, ama bir büyüklük sırası daha hızlı: parçacık olarak aynı işi yapar

function uniq(a) {
    var seen = {};
    return a.filter(function(item) {
        return seen.hasOwnProperty(item) ? false : (seen[item] = true);
    });
}

function uniq_fast(a) {
    var seen = {};
    var out = [];
    var len = a.length;
    var j = 0;
    for(var i = 0; i < len; i  ) {
         var item = a[i];
         if(seen[item] !== 1) {
               seen[item] = 1;
               out[j  ] = item;
         }
    }
    return out;
}

/////

var r = [0,1,2,3,4,5,6,7,8,9],
    a = [],
    LEN = 1000,
    LOOPS = 1000;

while(LEN--)
    a = a.concat(r);

var d = new Date();
for(var i = 0; i < LOOPS; i  )
    uniq(a);
document.write('<br>uniq, ms/loop: '   (new Date() - d)/LOOPS)

var d = new Date();
for(var i = 0; i < LOOPS; i  )
    uniq_fast(a);
document.write('<br>uniq_fast, ms/loop: '   (new Date() - d)/LOOPS)

ES6

ES6 sağlar işleri çok daha kolay hale getirir Set nesne:

function uniq(a) {
  var seen = new Set();
  return a.filter(function(x) {
    return !seen.has(x) && seen.add(x);
  })
}

Ancak, eğer benzersiz öğeleri içeren bir dizi gerekiyorsa, neden en başından beri Set kullanmak için değil mi?

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • AmazonWireless

    AmazonWirele

    8 EYLÜL 2010
  • sebsebdouze

    sebsebdouze

    7 ŞUBAT 2008
  • superemposed

    superemposed

    25 Aralık 2007