Dapatkan semua nilai unik dalam array JavaScript (hapus duplikat)

1488

Saya memiliki sejumlah angka yang harus saya pastikan unik. Saya menemukan potongan kode di bawah di internet dan berfungsi dengan baik sampai array memiliki nol di dalamnya. Saya menemukan skrip lain di sini di Stack Overflow yang terlihat hampir persis seperti itu, tetapi tidak gagal.

Jadi demi membantu saya belajar, dapatkah seseorang membantu saya menentukan di mana skrip prototipe salah?

Array.prototype.getUnique = function() {
 var o = {}, a = [], i, e;
 for (i = 0; e = this[i]; i++) {o[e] = 1};
 for (e in o) {a.push (e)};
 return a;
}

Jawaban lain dari pertanyaan rangkap:

Pertanyaan serupa:

Mottie
sumber
3
@ Hippietrail Pertanyaan yang lebih tua itu adalah tentang menemukan dan mengembalikan hanya duplikat (saya juga bingung!). Pertanyaan saya lebih lanjut tentang mengapa fungsi ini gagal ketika array memiliki nol di dalamnya.
Mottie
Anda mungkin ingin membuat judul pertanyaan Anda juga tidak terlalu kabur.
hippietrail
Untuk pembaca yang akan datang, ketika mulai menemukan bahwa Anda harus secara algoritmik memodifikasi konten struktur data Anda setiap saat, (memesannya, menghapus elemen berulang, dll.) Atau mencari elemen di dalamnya pada setiap iterasi, aman untuk mengasumsikan bahwa Anda Sedang menggunakan struktur data yang salah di tempat pertama dan mulai menggunakan yang lebih sesuai untuk tugas di tangan (dalam hal ini hash set bukannya array).
nurettin
Saya menyalin kode dari tempat lain, beberapa waktu yang lalu ... tetapi tampaknya cukup mudah: o= object, a= array, i= indexdan e= umm, sesuatu: P
Mottie
Kemungkinan rangkap dari Cara mendapatkan nilai unik dalam array
Adeel Imran

Jawaban:

2661

Dengan JavaScript 1.6 / ECMAScript 5 Anda dapat menggunakan filtermetode asli dari Array dengan cara berikut untuk mendapatkan array dengan nilai unik:

function onlyUnique(value, index, self) { 
    return self.indexOf(value) === index;
}

// usage example:
var a = ['a', 1, 'a', 2, '1'];
var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']

Metode asli filterakan mengulang melalui array dan hanya menyisakan entri yang melewati fungsi callback yang diberikan onlyUnique.

onlyUniquememeriksa, jika nilai yang diberikan adalah yang pertama kali terjadi. Jika tidak, itu harus duplikat dan tidak akan disalin.

Solusi ini berfungsi tanpa pustaka tambahan seperti jQuery atau prototype.js.

Ini berfungsi untuk array dengan tipe nilai campuran juga.

Untuk Browser lama (<ie9), yang tidak mendukung metode asli filterdan indexOfAnda dapat menemukan pekerjaan di dokumentasi MDN untuk filter dan indexOf .

Jika Anda ingin mempertahankan kemunculan nilai terakhir, gantikan indexOfdengan lastIndexOf.

Dengan ES6 bisa disingkat menjadi ini:

// usage example:
var myArray = ['a', 1, 'a', 2, '1'];
var unique = myArray.filter((v, i, a) => a.indexOf(v) === i); 

// unique is ['a', 1, 2, '1']

Terima kasih kepada Camilo Martin untuk petunjuk dalam komentar.

ES6 memiliki objek asli Setuntuk menyimpan nilai unik. Untuk mendapatkan array dengan nilai unik yang dapat Anda lakukan sekarang ini:

var myArray = ['a', 1, 'a', 2, '1'];

let unique = [...new Set(myArray)]; 

// unique is ['a', 1, 2, '1']

Konstruktor Setmengambil objek yang dapat ...diubah , seperti Array, dan operator spread mengubah set kembali menjadi Array. Terima kasih kepada Lukas Liese untuk petunjuk dalam komentar.

TLindig
sumber
55
Solusi ini akan berjalan jauh lebih lambat, sayangnya. Anda mengulang dua kali, sekali dengan filter dan sekali dengan indeks
Jack Franzen
19
@ JackFranzen Lebih lambat dari apa? Solusi dari Rafael ? Solusi Rafaels tidak berfungsi untuk array tipe campuran. Sebagai contoh saya, ['a', 1, 'a', 2, '1']Anda akan mendapatkan ['a', 1, 2]. Tapi ini bukan yang saya harapkan. BTW, jauh lebih lambat sangat relatif.
TLindig
25
Dalam JS modern: .filter((v,i,a)=>a.indexOf(v)==i)(notasi panah gemuk).
Camilo Martin
164
let unique_values = [...new Set(random_array)]; developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Lukas Liesis
5
Untuk jawaban yang jauh lebih terperinci, termasuk banyak kemungkinan - seperti menyortir lebih dulu, dan berurusan dengan berbagai tipe data - lihat stackoverflow.com/a/9229821/368896
Dan Nissenbaum
876

Diperbarui jawaban untuk ES6 / ES2015 : Menggunakan Set , solusi garis tunggal adalah:

var items = [4,5,4,6,3,4,5,2,23,1,4,4,4]
var uniqueItems = Array.from(new Set(items))

Yang kembali

[4, 5, 6, 3, 2, 23, 1]

Seperti yang disarankan le_m , ini juga dapat disingkat menggunakan operator spread , seperti

var uniqueItems = [...new Set(items)]
DI
sumber
11
Perhatikan, susunan dalam itu tidak berfungsiArray.from(new Set([[1,2],[1,2],[1,2,3]]))
Alexander Goncharov
3
Kinerja solusi ini dibandingkan dengan myArray.filter((v, i, a) => a.indexOf(v) === i);?
Simoyw
43
Harap dicatat bahwa jika Anda menggunakan Setdan menambahkan objek alih-alih nilai primitif itu akan berisi referensi unik ke objek. Dengan demikian set sin let s = new Set([{Foo:"Bar"}, {Foo:"Bar"}]);akan mengembalikan ini: Set { { Foo: 'Bar' }, { Foo: 'Bar' } }yang merupakan Setreferensi objek unik ke objek yang berisi nilai yang sama. Jika Anda menulis let o = {Foo:"Bar"};dan kemudian membuat satu set dengan dua referensi seperti let s2 = new Set([o,o]);Set { { Foo: 'Bar' } }
:,
2
Kedua opsi ini memiliki masalah pada IE10 bahkan dengan lapisan polyfill.io hadir
Thymine
2
test case baru jsperf.com/array-filter-unique-vs-new-set/1 tampak seperti new Settrofi
shuk
167

Saya menyadari pertanyaan ini sudah memiliki lebih dari 30 jawaban. Tetapi saya sudah membaca semua jawaban yang ada terlebih dahulu dan melakukan penelitian sendiri.

Saya membagi semua jawaban ke 4 solusi yang mungkin:

  1. Gunakan fitur ES6 baru: [...new Set( [1, 1, 2] )];
  2. Gunakan objek { }untuk mencegah duplikat
  3. Gunakan array pembantu [ ]
  4. Menggunakan filter + indexOf

Berikut kode contoh yang ditemukan dalam jawaban:

Gunakan fitur ES6 baru: [...new Set( [1, 1, 2] )];

function uniqueArray0(array) {
  var result = Array.from(new Set(array));
  return result    
}

Gunakan objek { }untuk mencegah duplikat

function uniqueArray1( ar ) {
  var j = {};

  ar.forEach( function(v) {
    j[v+ '::' + typeof v] = v;
  });

  return Object.keys(j).map(function(v){
    return j[v];
  });
} 

Gunakan array pembantu [ ]

function uniqueArray2(arr) {
    var a = [];
    for (var i=0, l=arr.length; i<l; i++)
        if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
            a.push(arr[i]);
    return a;
}

Menggunakan filter + indexOf

function uniqueArray3(a) {
  function onlyUnique(value, index, self) { 
      return self.indexOf(value) === index;
  }

  // usage
  var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']

  return unique;
}

Dan saya bertanya-tanya mana yang lebih cepat. Saya telah membuat sampel Google Sheet untuk menguji fungsi. Catatan: ECMA 6 tidak tersedia di Google Sheets, jadi saya tidak bisa mengujinya.

Inilah hasil tes: masukkan deskripsi gambar di sini

Saya berharap melihat bahwa kode yang menggunakan objek { }akan menang karena menggunakan hash. Jadi saya senang bahwa tes menunjukkan hasil terbaik untuk algoritma ini di Chrome dan IE. Terima kasih kepada @rab untuk kodenya .

Max Makhrov
sumber
Opsi "filter + indexOf" sangat lambat pada array lebih dari 100.000 item. Saya harus menggunakan pendekatan "objek peta" namun itu merusak penyortiran asli.
liberborn
Apakah angka yang lebih tinggi lebih lambat, tidak lebih cepat?
fletchsod
3
@ fletchsod, angka adalah waktu dalam ms untuk menjalankan kode.
Max Makhrov
1
Jumlahnya wong! Skrip Google apps berjalan di server mereka, bukan di browser klien - dan karenanya kinerja di Chrome / IE (atau hampir semua browser) akan sama!
Jay Dadhania
1
Meskipun dimungkinkan untuk menjalankan JS sisi klien dari Google Script (baik melalui google.script.host atau google.script.run - tidak yakin yang mana), jawabannya jelas menyatakan bahwa "ECMA 6 tidak tersedia di Google Sheets" - oleh karena itu kita dapat dengan aman berasumsi bahwa poster tersebut menggunakan Google Script sisi-server untuk ini - dan dengan demikian jawabannya menunjukkan kinerja Server Google, bukan browser !!
Jay Dadhania
134

Anda juga dapat menggunakan underscore.js .

console.log(_.uniq([1, 2, 1, 3, 1, 4]));
<script src="http://underscorejs.org/underscore-min.js"></script>

yang akan kembali:

[1, 2, 3, 4]
kornfridge
sumber
22
Tolong lakukan ini orang-orang. Jangan dongkrak sesuatu ke prototipe Array. Silahkan.
Jacob Dalton
5
@ Jacobalton - Ini bukan memperpanjang prototipe Array. Itu namespaced di objek _.
superluminary
25
@superluminary Saya tahu itu sebabnya saya katakan tolong lakukan ini. Solusi yang diterima menyarankan untuk memodifikasi prototipe Array. JANGAN lakukan itu.
Jacob Dalton
21
@ Jacobalton Tolong jangan lakukan ini. Tidak perlu menambahkan perpustakaan tambahan hanya untuk pekerjaan kecil yang bisa dilakukanarray = [...new Set(array)]
3
Ini mengalahkan tujuan menggunakan fitur ES dan menambahkan lebih banyak perpustakaan hanya mengasapi situs web lebih banyak.
fletchsod
68

Satu Liner, JavaScript Murni

Dengan sintaks ES6

list = list.filter((x, i, a) => a.indexOf(x) == i)

x --> item in array
i --> index of item
a --> array reference, (in this case "list")

masukkan deskripsi gambar di sini

Dengan sintaks ES5

list = list.filter(function (x, i, a) { 
    return a.indexOf(x) == i; 
});

Kompatibilitas Browser : IE9 +

Vamsi
sumber
14
@Spets Ini memiliki biaya kuadrat, jadi itu bukan jawaban terbaik
Oriol
@Buat seperti semua unik / berbeda ... ya, cerdas, gunakan radix untuk mengurutkan pertama, lebih lambat dari 0 (n2) pencarian cepat dalam banyak kasus.
doker
terima kasih kawan! Tidak menyadarinya ketika saya pertama kali melihat kode tetapi sekarang sedikit lebih jelas.
Spesialis
51

Saya telah menemukan metode bagus yang menggunakan jQuery

arr = $.grep(arr, function(v, k){
    return $.inArray(v ,arr) === k;
});

Catatan: Kode ini diambil dari pos tinju bebek Paul Irish - Saya lupa memberi kredit: P

Mottie
sumber
8
Solusi singkat, tetapi memanggil inArray jauh lebih efisien daripada memanggil hasOwnProperty.
Tuan Smith
Ini juga O (N ^ 2), kan? Sedangkan pendekatan kamus atau hasOwnProperty kemungkinan akan menjadi O (N * logN).
speedplane
Ini bekerja untuk saya, semua solusi lain tidak didukung menjadi Internet Explorer.
Kerl
51

Solusi terpendek dengan ES6: [...new Set( [1, 1, 2] )];

Atau jika Anda ingin memodifikasi prototipe Array (seperti pada pertanyaan awal):

Array.prototype.getUnique = function() {
    return [...new Set( [this] )];
};

EcmaScript 6 hanya sebagian diimplementasikan di browser modern saat ini (Agustus 2015), tetapi Babel telah menjadi sangat populer untuk mentransformasikan ES6 (dan bahkan ES7) kembali ke ES5. Dengan begitu Anda dapat menulis kode ES6 hari ini!

Jika Anda bertanya-tanya apa ...artinya, itu disebut operator penyebaran . Dari MDN : «Operator spread memungkinkan ekspresi diperluas di tempat-tempat di mana banyak argumen (untuk panggilan fungsi) atau beberapa elemen (untuk literal array) diharapkan». Karena Set adalah iterable (dan hanya dapat memiliki nilai unik), operator spread akan memperluas Set untuk mengisi array.

Sumber daya untuk belajar ES6:

Torsten Becker
sumber
3
Anda dapat melakukannya bahkan lebih pendek, dengan a = [...Set(a)], tetapi, bagaimanapun, ini hanya Firefox, untuk saat ini.
c69
@ c69, benar, tidak akan lebih pendek dari itu. Pengguna SpiderMonkey juga akan menghargai.
Torsten Becker
Bekerja dengan Babel. Anda hanya perlu menyertakan Array. Dari shim juga:require ( "core-js/fn/array/from" );
Vladislav Rastrusny
seharusnya Array.prototype.getUnique = function () {return [... new Set ([this])]; }; atau, Array.prototype.getUnique = function () {return [... new Set (this)]; }; Saya menerapkannya pada pertandingan $-berikut ('tubuh'). Html (). ToLowerCase (). (/ ([A-zA-Z0-9 ._ + -] + @ [a-zA-Z0-9. _-] + \. [a-zA-Z0-9 ._-] +) / gi) .getUnique (); Yang pertama mengembalikan saya satu nilai unik hanya di mana yang kedua mengembalikan semua menghapus duplikat.
ashique
[...Set(['a', 1, 'a', 2, '1'])]akan melemparkan TypeError, jadi masih bijaksana untuk mempertahankan new:[...new Set(['a', 1, 'a', 2, '1'])]
Adam Katz
36

Solusi paling sederhana:

var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
console.log([...new Set(arr)]);

Atau:

var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
console.log(Array.from(new Set(arr)));

Pedro L.
sumber
4
Perhatikan bahwa ini tidak didukung pada IE10 dan di bawah ini. Perhatikan bahwa IE11 + dan Safari menawarkan dukungan terbatas (bahkan tidak yakin bahwa contoh di atas berfungsi) developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
oriadam
32

Cara paling sederhana, dan tercepat (di Chrome) untuk melakukan ini:

Array.prototype.unique = function() {
    var a = [];
    for (var i=0, l=this.length; i<l; i++)
        if (a.indexOf(this[i]) === -1)
            a.push(this[i]);
    return a;
}

Cukup menelusuri setiap item dalam array, menguji apakah item itu sudah ada dalam daftar, dan jika tidak, dorong ke array yang akan dikembalikan.

Menurut jsPerf, fungsi ini adalah yang tercepat yang bisa saya temukan di mana saja - silakan menambahkan sendiri.

Versi non-prototipe:

function uniques(arr) {
    var a = [];
    for (var i=0, l=arr.length; i<l; i++)
        if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
            a.push(arr[i]);
    return a;
}

Penyortiran

Ketika juga perlu mengurutkan array, berikut ini adalah yang tercepat:

Array.prototype.sortUnique = function() {
    this.sort();
    var last_i;
    for (var i=0;i<this.length;i++)
        if ((last_i = this.lastIndexOf(this[i])) !== i)
            this.splice(i+1, last_i-i);
    return this;
}

atau non-prototipe:

function sortUnique(arr) {
    arr.sort();
    var last_i;
    for (var i=0;i<arr.length;i++)
        if ((last_i = arr.lastIndexOf(arr[i])) !== i)
            arr.splice(i+1, last_i-i);
    return arr;
}

Ini juga lebih cepat daripada metode di atas di sebagian besar browser non-chrome.

Joeytje50
sumber
Di Linux, Chrome 55.0.2883 lebih suka arr.unique () dan arrclone2.sortFilter swilliams Anda () paling lambat (78% lebih lambat). Namun, Firefox 51.0.0 (dengan banyak addons) memiliki swilliams sebagai yang tercepat (namun masih lebih lambat oleh Ops / detik daripada hasil Chrome lainnya) dengan jQuery $ .grep (arr, jqFilter) paling lambat (46% lebih lambat). Arr.uniq Anda () lebih lambat 30%. Saya menjalankan setiap tes dua kali dan mendapatkan hasil yang konsisten. Arr.getUnique Rafael () mendapat tempat kedua di kedua browser.
Adam Katz
jsPerf adalah kereta pada saat ini, jadi saya edit untuk tes ini tidak melakukan segala sesuatu, tapi itu hasil dalam menambahkan dua tes: Cocco ini toUnique () mengalahkan Vamsi ini ES6 list.filter () pada kedua browser, mengalahkan swilliams' sortFilter () untuk # 1 di FF (sortFilter 16% lebih lambat) dan mengalahkan pengujian Anda yang diurutkan (yang lebih lambat 2%) untuk # 3 di Chrome.
Adam Katz
Ah, saya belum mengetahui bahwa tes-tes itu kecil dan tidak terlalu penting. Sebuah komentar untuk jawaban yang diterima menjelaskan masalah itu dan menawarkan koreksi dalam revisi untuk tes, di mana kode Rafael mudah yang tercepat dan kode arr.unique Joetje50 adalah 98% lebih lambat. Saya juga membuat revisi lain seperti disebutkan dalam komentar ini .
Adam Katz
1
Sebenarnya, algoritma yang Anda implementasikan dalam uniquefungsi memiliki kompleksitas O (n ^ 2) sementara yang di getUniquedalamnya adalah O (n). Yang pertama mungkin lebih cepat pada set data kecil, tetapi bagaimana Anda bisa berdebat dengan matematika :) Anda dapat memastikan yang terakhir lebih cepat jika Anda menjalankannya pada array, katakanlah, 1e5 item unik
Mikhail Dudin
31

HANYA KINERJA! kode ini mungkin 10X lebih cepat dari semua kode di sini * berfungsi pada semua browser dan juga memiliki dampak memori terendah .... dan banyak lagi

jika Anda tidak perlu menggunakan kembali larik lama; btw lakukan operasi lain yang diperlukan sebelum mengubahnya menjadi unik di sini mungkin cara tercepat untuk melakukan ini, juga sangat singkat.

var array=[1,2,3,4,5,6,7,8,9,0,1,2,1];

maka kamu bisa mencoba ini

var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 1];

function toUnique(a, b, c) { //array,placeholder,placeholder
  b = a.length;
  while (c = --b)
    while (c--) a[b] !== a[c] || a.splice(c, 1);
  return a // not needed ;)
}
console.log(toUnique(array));
//[3, 4, 5, 6, 7, 8, 9, 0, 2, 1]

Saya datang dengan fungsi ini membaca artikel ini ...

http://www.shamasis.net/2009/09/fast-algorithm-to-find-unique-items-in-javascript-array/

Saya tidak suka for loop. ia memiliki banyak parameter. saya suka loop while--. sedangkan loop tercepat di semua browser kecuali yang kita semua sangat suka ... chrome.

Lagi pula saya menulis fungsi pertama yang menggunakan while. Dan ya itu sedikit lebih cepat daripada fungsi yang ditemukan dalam artikel.tapi tidak cukup.unique2()

langkah selanjutnya gunakan js modern. Object.keys saya mengganti yang lain untuk loop dengan Object.keys js1.7 ... sedikit lebih cepat dan lebih pendek (di krom 2x lebih cepat);). Tidak cukup!. unique3().

pada titik ini saya sedang berpikir tentang apa yang sebenarnya saya butuhkan dalam fungsi unik SAYA. saya tidak memerlukan array lama, saya ingin fungsi cepat. jadi saya menggunakan 2 saat loop + sambatan.unique4()

Tidak ada gunanya mengatakan bahwa saya terkesan.

chrome: 150.000 operasi per detik yang biasa melonjak menjadi 1.800.000 operasi per detik.

yaitu: 80.000 op / s vs 3.500.000 op / s

ios: 18.000 op / s vs 170.000 op / s

safari: 80.000 op / s vs 6.000.000 op / s

Bukti http://jsperf.com/wgu atau lebih baik gunakan console.time ... microtime ... terserah

unique5() hanya untuk menunjukkan kepada Anda apa yang terjadi jika Anda ingin mempertahankan array yang lama.

Jangan gunakan Array.prototypejika kamu tidak tahu apa yang kamu lakukan. Saya hanya melakukan banyak salinan dan masa lalu. Gunakan Object.defineProperty(Array.prototype,...,writable:false,enumerable:false})jika Anda ingin membuat prototipe asli.contoh: https://stackoverflow.com/a/20463021/2450730

Demo http://jsfiddle.net/46S7g/

CATATAN: array lama Anda hancur / menjadi unik setelah operasi ini.

jika Anda tidak dapat membaca kode di atas tanyakan, baca buku javascript atau di sini ada beberapa penjelasan tentang kode pendek. https://stackoverflow.com/a/21353032/2450730

beberapa menggunakan indexOf ... jangan ... http://jsperf.com/dgfgghfghfghghgfhgfhfghfhgfh

untuk array kosong

!array.length||toUnique(array); 
cocco
sumber
4
diuji pada node.js, dengan array 100k dari Url (string). Hasilnya 2x lebih lambat dari underscore.js _.uniq ... walaupun jsperf terpisah setuju dengan Anda ( jsperf.com/uniq-performance/5 ), saya kecewa :(
xShirase
3
Anda tidak menguji dengan benar di jsperf ... dalam contoh Anda, Anda menentukan fungsi setiap kali ... tetapi fungsi underscore.js sudah ditentukan .. ini menghukum fungsi saya. juga menguji 3 & 4. Hal lain yang harus saya katakan adalah bahwa jika Anda menggunakan variabel campuran (string & angka) Anda harus mengganti [b]! == a [c] dengan [b]! = a [c]
cocco
2
Saya tidak yakin apakah jsPerf benar, tetapi tampaknya alternatif Mengurangi (bagi saya lebih mudah dipahami) agak 94% lebih cepat daripada solusi Anda. jsperf.com/reduce-for-distinct Edit: Milik Anda lebih lambat pada chrome, sama pada Edge dan lebih cepat pada Firefox.
Victor Ivens
3
Hanya dapat digunakan dengan array kecil / persentase duplikat rendah . Setiap kali objek yang tidak unik ditemukan, mesin akan dipaksa untuk menggeser semua elemen lainnya ke kiri, dengan: 1) mengulanginya 2) membacanya 3) membacanya 3) menulisnya ke lokasi baru. Dan kemudian, ia juga menciptakan array baru dengan satu elemen yang disambungkan, dan mengembalikannya sebagai hasilnya ... Algoritma dengan cepat menurun dengan array yang lebih besar / duplikat yang lebih sering. Untuk array ukuran 1000-> 10000-> 50.000 dan ~ 40% duplikat, rata-rata waktu yang dibutuhkan akan seperti 2-> 775-> 19113 ms. (ukuran berubah sebagai 1-> x10-> x5, waktu 1-> x10-> x25) di Chrome.
ankhzet
1
Terima kasih. Pendekatan yang bagus. Tapi bagaimana dengan pesanan barang yang benar?
liberborn
28

Banyak jawaban di sini mungkin tidak berguna untuk pemula. Jika menghapus duplikat array sulit, apakah mereka benar-benar tahu tentang rantai prototipe, atau bahkan jQuery?

Di browser modern, solusi bersih dan sederhana adalah menyimpan data dalam Set , yang dirancang untuk menjadi daftar nilai unik.

const cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
const uniqueCars = Array.from(new Set(cars));

Ini Array.fromberguna untuk mengonversi Set kembali ke Array sehingga Anda memiliki akses mudah ke semua metode (fitur) mengagumkan yang dimiliki array. Ada juga cara lain untuk melakukan hal yang sama. Tetapi Anda mungkin tidak perlu Array.fromsama sekali, karena Sets memiliki banyak fitur berguna seperti forEach .

Jika Anda perlu mendukung Internet Explorer lama, dan dengan demikian tidak dapat menggunakan Set, maka teknik sederhana adalah menyalin item ke array baru sambil memeriksa sebelumnya apakah mereka sudah ada dalam array baru.

// Create a list of cars, with duplicates.
var cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
// Create a list of unique cars, to put a car in if we haven't already.
var uniqueCars = [];

// Go through each car, one at a time.
cars.forEach(function (car) {
    // The code within the following block runs only if the
    // current car does NOT exist in the uniqueCars list
    // - a.k.a. prevent duplicates
    if (uniqueCars.indexOf(car) === -1) {
        // Since we now know we haven't seen this car before,
        // copy it to the end of the uniqueCars list.
        uniqueCars.push(car);
    }
});

Untuk membuat ini dapat digunakan kembali secara instan, mari kita fungsi.

function deduplicate(data) {
    if (data.length > 0) {
        var result = [];

        data.forEach(function (elem) {
            if (result.indexOf(elem) === -1) {
                result.push(elem);
            }
        });

        return result;
    }
}

Jadi untuk menghilangkan duplikat, sekarang kita akan melakukan ini.

var uniqueCars = deduplicate(cars);

The deduplicate(cars)bagian menjadi hal yang kami beri nama hasil ketika selesai fungsi.

Berikan nama array yang Anda suka.

Seth Holladay
sumber
Ngomong-ngomong, saya menggunakan array yang penuh string untuk menunjukkan bahwa teknik saya fleksibel. Ini akan bekerja dengan baik untuk angka.
Seth Holladay
20
["Defects", "Total", "Days", "City", "Defects"].reduce(function(prev, cur) {
  return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev;
 }, []);

[0,1,2,0,3,2,1,5].reduce(function(prev, cur) {
  return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev;
 }, []);
sergeyz
sumber
Bisakah Anda menjelaskan mengapa Anda tidak hanya pushelemen ke array daripada menggunakan concat? Saya mencoba menggunakan push dan gagal. Saya mencari penjelasan.
makenova
1
Alasannya adalah dalam nilai balik. concat mengembalikan array yang dimodifikasi (persis apa yang perlu dikembalikan di dalam fungsi pengurangan), sementara push mengembalikan indeks di mana Anda dapat mengakses nilai yang didorong. Apakah itu menjawab pertanyaan Anda?
sergeyz
Rupanya, solusi ini cukup cepat di chrome (dan node). jsperf.com/reduce-for-distinct Itulah versi ES6: [0,1,2,0,3,2,1,5].reduce((prev, cur) => ~prev.indexOf(cur) ? prev : prev.concat([cur]), []);
Victor Ivens
side note: implementasi ini tidak NaN-ramah
Alireza
19

Kita bisa melakukan ini menggunakan set ES6:

var duplicatedArray = [1, 2, 3, 4, 5, 1, 1, 1, 2, 3, 4];
var uniqueArray = Array.from(new Set(duplicatedArray));

console.log(uniqueArray);

// Keluarannya adalah

uniqueArray = [1,2,3,4,5];
chinmayan
sumber
17

Prototipe getUniqueini tidak sepenuhnya benar, karena jika saya memiliki array seperti: ["1",1,2,3,4,1,"foo"]itu akan kembali ["1","2","3","4"]dan "1"adalah string dan 1merupakan bilangan bulat; mereka berbeda.

Inilah solusi yang benar:

Array.prototype.unique = function(a){
    return function(){ return this.filter(a) }
}(function(a,b,c){ return c.indexOf(a,b+1) < 0 });

menggunakan:

var foo;
foo = ["1",1,2,3,4,1,"foo"];
foo.unique();

Di atas akan menghasilkan ["1",2,3,4,1,"foo"].

Gabriel Silveira
sumber
1
Perhatikan bahwa $foo = 'bar'ini adalah cara PHP untuk mendeklarasikan variabel. Ini akan bekerja dalam javascript, tetapi akan membuat global tersirat, dan umumnya tidak boleh dilakukan.
Camilo Martin
@CamiloMartin maaf tetapi Anda salah, $ foo bersifat global karena contohnya tidak ada dalam penutupan dan dia kehilangan kata kunci var. Tidak ada hubungannya dengan dolar jsfiddle.net/robaldred/L2MRb
Rob
8
@Rob itulah yang saya katakan, orang-orang PHP akan berpikir $fooadalah cara mendeklarasikan variabel dalam javascript sementara sebenarnya var foo.
Camilo Martin
13

Tanpa memperluas Array.prototype (dikatakan praktik yang buruk) atau menggunakan jquery / garis bawah, Anda dapat dengan mudah filtermenggunakan array.

Dengan menjaga kejadian terakhir:

    function arrayLastUnique(array) {
        return array.filter(function (a, b, c) {
            // keeps last occurrence
            return c.indexOf(a, b + 1) < 0;
        });
    },

atau kejadian pertama:

    function arrayFirstUnique(array) {
        return array.filter(function (a, b, c) {
            // keeps first occurrence
            return c.indexOf(a) === b;
        });
    },

Yah, ini hanya javascript ECMAScript 5+, yang berarti hanya IE9 +, tapi bagus untuk pengembangan HTML / JS asli (Aplikasi Windows Store, Firefox OS, Sencha, Phonegap, Titanium, ...).

Cur
sumber
2
Fakta bahwa ini js 1.6 tidak berarti Anda tidak dapat menggunakannya filter. Di halaman MDN mereka memiliki implementasi untuk Internet Explorer, maksud saya, browser yang lebih lama. Juga: JS 1.6 hanya merujuk ke mesin js Firefox, tetapi hal yang benar untuk mengatakan itu adalah ECMAScript 5.
Camilo Martin
@CamiloMartin Saya mengubah 1,6 menjadi ECMAScript5. Terima kasih.
Cœur
13

Sihir

a.filter(e=>!(t[e]=e in t)) 

O (n) kinerja ; kami menganggap array Anda ada di adan t={}. Penjelasan di sini (+ Jeppe impr.)

Kamil Kiełczewski
sumber
14
ini terlihat sangat keren, bahwa tanpa penjelasan yang kuat aku jatuh kamu akan menambang bitcoin ketika aku menjalankan ini
Ondřej Želazko
3
yang saya maksud adalah bahwa Anda harus memperluas jawaban Anda dengan beberapa penjelasan dan berkomentar dekonstruksi itu. jangan berharap orang akan menemukan jawaban yang berguna seperti ini. (meskipun itu benar-benar terlihat keren mungkin berhasil)
Ondřej Želazko
1
@ Jeppe ketika saya menjalankan peningkatan Anda maka saya mengalami efek aha (sebelum saya tidak tahu bahwa saya dapat menggunakan inoperator di luar konstruksi selain forloop: P) - Terima kasih - Saya menghargai itu dan akan memberikan +2 untuk jawaban Anda yang baik lainnya .
Kamil Kiełczewski
2
bukankah itu membuat variabel global tyang tetap hidup setelah pemfilteran ... ??
philipp
1
Ini benar-benar solusi yang sulit. Sayangnya, Anda harus mendeklarasikan t di luar ekspresi kecuali jika Anda ingin mendefinisikan variabel global dan / atau mengandalkan bundler modul Anda untuk menyembunyikan global. Itu terlihat mewah, tetapi bantulah diri Anda sendiri (dan tim dev Anda) dan cukup tulis dua baris saja: let t = {}; a.filter (e =>! (t [e] = e in t))
ford04
13
[...new Set(duplicates)]

Ini adalah yang paling sederhana dan dirujuk dari MDN Web Documents .

const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
console.log([...new Set(numbers)]) // [2, 3, 4, 5, 6, 7, 32]
kode ifelse
sumber
Sementara kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan tentang bagaimana dan mengapa ini menyelesaikan masalah akan sangat membantu untuk meningkatkan kualitas posting Anda, dan mungkin menghasilkan lebih banyak suara. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, bukan hanya orang yang bertanya sekarang. Harap edit jawaban Anda untuk menambahkan penjelasan, dan berikan indikasi batasan dan asumsi apa yang berlaku.
id.ot
11

Jika Anda menggunakan kerangka kerja Prototipe tidak perlu melakukan loop 'for', Anda dapat menggunakan http://www.prototypejs.org/api/array/uniq seperti ini:

var a = Array.uniq();  

Yang akan menghasilkan array duplikat tanpa duplikat. Saya menemukan pertanyaan Anda mencari metode untuk menghitung catatan array yang berbeda

uniq ()

Saya menggunakan

ukuran()

dan ada hasil sederhana saya. ps Maaf jika saya salah menuliskan sesuatu

sunting: jika Anda ingin lepas dari catatan yang tidak ditentukan, Anda mungkin ingin menambahkan

kompak ()

sebelumnya, seperti ini:

var a = Array.compact().uniq();  
Decebal
sumber
14
karena saya menemukan jawaban yang lebih baik, saya berpikir tentang topik adalah untuk semua orang, bukan hanya untuk orang yang bertanya
Decebal
11

Sekarang menggunakan set Anda dapat menghapus duplikat dan mengubahnya kembali ke array.

var names = ["Mike","Matt","Nancy", "Matt","Adam","Jenny","Nancy","Carl"];

console.log([...new Set(names)])

Solusi lain adalah dengan menggunakan sort & filter

var names = ["Mike","Matt","Nancy", "Matt","Adam","Jenny","Nancy","Carl"];
var namesSorted = names.sort();
const result = namesSorted.filter((e, i) => namesSorted[i] != namesSorted[i+1]);
console.log(result);

Krishnadas PC
sumber
10

Itu karena 0merupakan nilai palsu dalam JavaScript.

this[i] akan menjadi falsy jika nilai array adalah 0 atau nilai falsy lainnya.

Luca Matteis
sumber
Ahhhh, ok saya mengerti sekarang ... tapi apakah akan ada perbaikan yang mudah untuk membuatnya bekerja?
Mottie
10
Array.prototype.getUnique = function() {
    var o = {}, a = []
    for (var i = 0; i < this.length; i++) o[this[i]] = 1
    for (var e in o) a.push(e)
    return a
}
singkat
sumber
Saya pikir ini tidak akan berfungsi jika array berisi objek / array, dan saya tidak yakin apakah itu akan mempertahankan jenis skalar.
Camilo Martin
Ya, semuanya akan terstruktur. Itu bisa diperbaiki dengan menyimpan nilai asli dalam obukan hanya a 1, meskipun perbandingan kesetaraan masih akan menjadi stringwise (meskipun, dari semua kemungkinan persamaan Javascript, sepertinya tidak terlalu tidak masuk akal).
ephemient
Array.prototype hanya dapat diperluas dengan metode yang tidak dapat dihitung .... Object.defineProperty (Array.prototype, "getUnique", {}) ... tetapi gagasan menggunakan objek pembantu sangat bagus
bortunac
10

Saya punya masalah yang sedikit berbeda di mana saya perlu menghapus objek dengan duplikat properti id dari sebuah array. ini berhasil.

let objArr = [{
  id: '123'
}, {
  id: '123'
}, {
  id: '456'
}];

objArr = objArr.reduce((acc, cur) => [
  ...acc.filter((obj) => obj.id !== cur.id), cur
], []);

console.log(objArr);

shunryu111
sumber
9

Jawaban paling sederhana adalah:

const array = [1, 1, 2, 2, 3, 5, 5, 2];
const uniqueArray = [...new Set(array)];
console.log(uniqueArray); // [1, 2, 3, 5]
Sukanta Bala
sumber
Sederhana tetapi tidak bekerja dengan berbagai objek.
Thanwa Ch.
7

Saya tidak yakin mengapa Gabriel Silveira menulis fungsi seperti itu tetapi bentuk yang lebih sederhana yang bekerja untuk saya dengan baik dan tanpa minifikasi adalah:

Array.prototype.unique = function() {
  return this.filter(function(value, index, array) {
    return array.indexOf(value, index + 1) < 0;
  });
};

atau dalam CoffeeScript:

Array.prototype.unique = ->
  this.filter( (value, index, array) ->
    array.indexOf(value, index + 1) < 0
  )
Dan Fox
sumber
7

Jika Anda baik-baik saja dengan dependensi tambahan, atau Anda sudah memiliki salah satu perpustakaan di basis kode Anda, Anda dapat menghapus duplikat dari array di tempat menggunakan LoDash (atau Underscore).

Pemakaian

Jika Anda belum memilikinya di basis kode, instal menggunakan npm:

npm install lodash

Kemudian gunakan sebagai berikut:

import _ from 'lodash';
let idArray = _.uniq ([
    1,
    2,
    3,
    3,
    3
]);
console.dir(idArray);

Di luar:

[ 1, 2, 3 ]
NikeshPathania
sumber
7

Ini telah dijawab banyak, tetapi tidak menjawab kebutuhan khusus saya.

Banyak jawaban seperti ini:

a.filter((item, pos, self) => self.indexOf(item) === pos);

Tapi ini tidak berfungsi untuk array objek kompleks.

Katakanlah kita memiliki array seperti ini:

const a = [
 { age: 4, name: 'fluffy' },
 { age: 5, name: 'spot' },
 { age: 2, name: 'fluffy' },
 { age: 3, name: 'toby' },
];

Jika kita menginginkan objek dengan nama unik, kita harus menggunakan array.prototype.findIndexalih-alih array.prototype.indexOf:

a.filter((item, pos, self) => self.findIndex(v => v.name === item.name) === pos);
Dave
sumber
Solusi hebat, berhati-hatilah karena array baru akan kembali dari suatu fungsi. (itu tidak memodifikasi dirinya sendiri)
Thanwa Ch.
6

Dari kompleksitas waktu blog Shamasis Bhattacharya (O (2n)):

Array.prototype.unique = function() {
    var o = {}, i, l = this.length, r = [];
    for(i=0; i<l;i+=1) o[this[i]] = this[i];
    for(i in o) r.push(o[i]);
    return r;
};

Dari blog Paul Irish : peningkatan pada JQuery .unique():

(function($){

    var _old = $.unique;

    $.unique = function(arr){

        // do the default behavior only if we got an array of elements
        if (!!arr[0].nodeType){
            return _old.apply(this,arguments);
        } else {
            // reduce the array to contain no dupes via grep/inArray
            return $.grep(arr,function(v,k){
                return $.inArray(v,arr) === k;
            });
        }
    };
})(jQuery);

// in use..
var arr = ['first',7,true,2,7,true,'last','last'];
$.unique(arr); // ["first", 7, true, 2, "last"]

var arr = [1,2,3,4,5,4,3,2,1];
$.unique(arr); // [1, 2, 3, 4, 5]
Frosty Z
sumber
6

Menemukan nilai Array unik dalam metode sederhana

function arrUnique(a){
  var t = [];
  for(var x = 0; x < a.length; x++){
    if(t.indexOf(a[x]) == -1)t.push(a[x]);
  }
  return t;
}
arrUnique([1,4,2,7,1,5,9,2,4,7,2]) // [1, 4, 2, 7, 5, 9]
Saravanan Rajaraman
sumber
6

Tampaknya kami telah kehilangan jawaban Rafael , yang berdiri sebagai jawaban yang diterima selama beberapa tahun. Ini (setidaknya di 2017) solusi berkinerja terbaik jika Anda tidak memiliki array tipe campuran :

Array.prototype.getUnique = function(){
    var u = {}, a = [];
    for (var i = 0, l = this.length; i < l; ++i) {
        if (u.hasOwnProperty(this[i])) {
            continue;
        }
        a.push(this[i]);
        u[this[i]] = 1;
    }
return a;
}

Jika Anda memang memiliki array tipe campuran, Anda bisa membuat serialisasi kunci hash:

Array.prototype.getUnique = function() {
    var hash = {}, result = [], key; 
    for ( var i = 0, l = this.length; i < l; ++i ) {
        key = JSON.stringify(this[i]);
        if ( !hash.hasOwnProperty(key) ) {
            hash[key] = true;
            result.push(this[i]);
        }
    }
    return result;
}
Jason
sumber
5

Untuk mengatasi masalah sebaliknya, mungkin berguna untuk tidak memiliki duplikat saat Anda memuat array Anda, cara Set objek akan melakukannya tetapi itu belum tersedia di semua browser. Menghemat memori dan lebih efisien jika Anda perlu melihat isinya berkali-kali.

Array.prototype.add = function (elem) {
   if (this.indexOf(elem) == -1) {
      this.push(elem);
   }
}

Sampel:

set = [];
[1,3,4,1,2,1,3,3,4,1].forEach(function(x) { set.add(x); });

Memberi anda set = [1,3,4,2]

Le Droid
sumber