Saya bekerja di JavaScript. Saya ingin menyimpan daftar nilai string unik , tidak berurutan, dengan properti berikut:
- cara cepat untuk bertanya 'apakah A ada dalam daftar'?
- cara cepat untuk melakukan 'hapus A dari daftar jika ada dalam daftar'
- cara cepat untuk melakukan 'tambahkan A ke daftar jika belum ada'.
Yang benar-benar saya inginkan adalah satu set. Adakah saran untuk cara terbaik meniru set di JavaScript?
Pertanyaan ini merekomendasikan menggunakan Obyek , dengan kunci menyimpan properti, dan semua nilai diatur ke true: apakah itu cara yang masuk akal?
javascript
Richard
sumber
sumber
Jawaban:
Jika Anda memprogram dalam lingkungan yang mendukung ES6 (seperti node.js, peramban khusus dengan kemampuan ES6 yang Anda butuhkan atau mengubah kode ES6 untuk lingkungan Anda), maka Anda dapat menggunakan
Set
objek yang dibangun ke dalam ES6 . Ini memiliki kemampuan yang sangat bagus dan dapat digunakan sebagaimana mestinya di lingkungan Anda.Untuk banyak hal sederhana di lingkungan ES5, menggunakan Object berfungsi dengan sangat baik. Jika
obj
objek Anda danA
merupakan variabel yang memiliki nilai yang ingin Anda operasikan di set, maka Anda bisa melakukan ini:Kode inisialisasi:
Pertanyaan 1: Ada
A
dalam daftar:Pertanyaan 2: Hapus 'A' dari daftar jika ada:
Pertanyaan 3: Tambahkan 'A' ke daftar jika belum ada
Untuk kelengkapan, tes untuk apakah
A
ada dalam daftar sedikit lebih aman dengan ini:karena potensi konflik antara metode bawaan dan / atau properti pada Objek dasar seperti
constructor
properti.Bilah sisi pada ES6: Versi ECMAScript 6 saat ini atau yang disebut ES 2015 memiliki objek Set bawaan . Ini diterapkan sekarang di beberapa browser. Karena ketersediaan browser berubah dari waktu ke waktu, Anda dapat melihat baris
Set
di dalam tabel kompatibilitas ES6 ini untuk melihat status ketersediaan browser saat ini.Salah satu keuntungan dari objek Set bawaan adalah bahwa ia tidak memaksa semua kunci ke string seperti Object sehingga Anda dapat memiliki 5 dan "5" sebagai kunci yang terpisah. Dan, Anda bahkan dapat menggunakan Objek secara langsung di set tanpa konversi string. Berikut adalah artikel yang menjelaskan beberapa kemampuan dan dokumentasi MDN tentang objek Set.
Saya sekarang telah menulis polyfill untuk objek set ES6 sehingga Anda bisa mulai menggunakannya sekarang dan secara otomatis akan tunduk pada objek set bawaan jika browser mendukungnya. Ini memiliki keuntungan bahwa Anda sedang menulis kode yang kompatibel ES6 yang akan bekerja sepanjang jalan kembali ke IE7. Tapi, ada beberapa kelemahannya. Set antarmuka ES6 mengambil keuntungan dari ES6 iterators sehingga Anda dapat melakukan hal-hal seperti
for (item of mySet)
dan itu akan secara otomatis beralih melalui set untuk Anda. Namun, fitur bahasa jenis ini tidak dapat diimplementasikan melalui polyfill. Anda masih dapat mengulangi set ES6 tanpa menggunakan fitur bahasa ES6 baru, tetapi terus terang tanpa fitur bahasa baru, itu tidak senyaman antarmuka set lain yang saya sertakan di bawah ini.Anda dapat memutuskan mana yang paling cocok untuk Anda setelah melihat keduanya. Kumpulan polyfill ES6 ada di sini: https://github.com/jfriend00/ES6-Set .
FYI, dalam pengujian saya sendiri, saya perhatikan bahwa implementasi Firefox v29 Set tidak sepenuhnya mutakhir pada draft spesifikasi saat ini. Misalnya, Anda tidak dapat membuat
.add()
panggilan metode seperti yang dijelaskan oleh spec dan dukungan polyfill saya. Ini mungkin masalah spesifikasi yang bergerak karena belum selesai.Objek Set Pra-Bangun: Jika Anda ingin objek yang sudah dibangun yang memiliki metode untuk beroperasi pada set yang dapat Anda gunakan di browser apa pun, Anda dapat menggunakan serangkaian objek pra-bangun yang berbeda yang menerapkan berbagai jenis set. Ada miniSet yang merupakan kode kecil yang mengimplementasikan dasar-dasar objek yang ditetapkan. Ini juga memiliki objek set kaya lebih banyak fitur dan beberapa derivasi termasuk Kamus (mari kita menyimpan / mengambil nilai untuk setiap kunci) dan ObjectSet (mari kita menyimpan satu set objek - objek JS atau objek DOM di mana Anda menyediakan fungsi yang menghasilkan kunci unik untuk masing-masing atau ObjectSet akan menghasilkan kunci untuk Anda).
Berikut adalah salinan kode untuk miniSet (kode paling baru ada di github ).
sumber
Object.keys(obj)
.Object.keys()
perlu IE9, FF4, Safari 5, Opera 12 atau lebih tinggi. Ada polyfill untuk browser lama di sini .obj.hasOwnProperty(prop)
untuk cek keanggotaan. GunakanObject.prototype.hasOwnProperty.call(obj, prop)
sebagai gantinya, yang bekerja bahkan jika "set" berisi nilai"hasOwnProperty"
.Anda dapat membuat Obyek tanpa properti seperti
yang dapat bertindak sebagai satu set dan menghilangkan kebutuhan untuk digunakan
hasOwnProperty
.sumber
set = {}
itu akan mewarisi semua sifat-sifat dari Object (misalnyatoString
), sehingga Anda akan harus memeriksa untuk payload dari himpunan (properti Anda ditambahkan) denganhasOwnProperty
diif (A in set)
set[A]=true
pernyataan untuk setiap elemen yang ingin Anda tambahkan, bukan hanya satu penginisialisasi?s = Object.create(null);s["thorben"] = true;ss = Object.create(s)
Pada ECMAScript 6, struktur data Set adalah fitur bawaan . Kompatibilitas dengan versi node.js dapat ditemukan di sini .
sumber
in
tidak berfungsi karenaSet
objek tidak memiliki elemen sebagai properti, yang akan menjadi buruk karena set dapat memiliki elemen jenis apa pun, tetapi properti adalah string. Anda dapat menggunakanhas
:Set([1,2]).has(1)
Di Javascript versi ES6, Anda memiliki tipe bawaan untuk set ( periksa kompatibilitas dengan browser Anda ).
Untuk menambahkan elemen ke set yang Anda gunakan
.add()
, yang berjalan diO(1)
dan menambahkan elemen ke set (jika tidak ada) atau tidak melakukan apa-apa jika sudah ada di sana. Anda dapat menambahkan elemen jenis apa pun di sana (array, string, angka)Untuk memeriksa jumlah elemen dalam set, Anda cukup menggunakan
.size
. Juga berjalan diO(1)
Untuk menghapus elemen dari set penggunaan
.delete()
. Mengembalikan nilai true jika nilainya ada di sana (dan telah dihapus), dan false jika nilainya tidak ada. Juga berjalan diO(1)
.Untuk memeriksa apakah elemen tersebut ada dalam set yang digunakan
.has()
, yang mengembalikan true jika elemen tersebut di set dan false sebaliknya. Juga berjalan diO(1)
.Selain metode yang Anda inginkan, ada beberapa metode tambahan:
numbers.clear();
hanya akan menghapus semua elemen dari setnumbers.forEach(callback);
iterasi melalui nilai-nilai set dalam urutan penyisipannumbers.entries();
buat iterator dari semua nilainumbers.keys();
mengembalikan kunci set yang sama dengannumbers.values()
Ada juga Weakset yang memungkinkan untuk menambahkan hanya nilai tipe objek.
sumber
.add()
running di O (1)? Saya tertarik dengan ini,Saya telah memulai implementasi Sets yang saat ini bekerja cukup baik dengan angka dan string. Fokus utama saya adalah operasi perbedaan, jadi saya mencoba membuatnya seefisien mungkin. Ulasan fork dan kode dipersilakan!
https://github.com/mcrisc/SetJS
sumber
Saya hanya memperhatikan bahwa perpustakaan d3.js memiliki implementasi set, peta dan struktur data lainnya. Saya tidak dapat berdebat tentang efisiensi mereka tetapi menilai dari fakta bahwa itu adalah perpustakaan yang populer, itu pasti yang Anda butuhkan.
Dokumentasinya ada di sini
Untuk kenyamanan saya salin dari tautan (3 fungsi pertama adalah yang menarik)
Membangun set baru. Jika array ditentukan, tambahkan array nilai string yang diberikan ke set yang dikembalikan.
Mengembalikan nilai true jika dan hanya jika set ini memiliki entri untuk string nilai yang ditentukan.
Menambahkan string nilai yang ditentukan ke set ini.
Jika set berisi string nilai yang ditentukan, hapus dan mengembalikan true. Jika tidak, metode ini tidak melakukan apa pun dan mengembalikan false.
Mengembalikan array nilai string di set ini. Urutan nilai yang dikembalikan adalah arbitrer. Dapat digunakan sebagai cara yang nyaman untuk menghitung nilai-nilai unik untuk serangkaian string. Sebagai contoh:
d3.set (["foo", "bar", "foo", "baz"]). values (); // "foo", "bar", "baz"
Memanggil fungsi yang ditentukan untuk setiap nilai dalam set ini, meneruskan nilai sebagai argumen. Konteks fungsi ini adalah himpunan ini. Pengembalian tidak terdefinisi. Urutan iterasi bersifat arbitrer.
Mengembalikan nilai true jika dan hanya jika set ini memiliki nilai nol.
Mengembalikan jumlah nilai dalam set ini.
sumber
Ya, itu cara yang masuk akal - itu saja objek (untuk kasus penggunaan ini) - banyak kunci / nilai dengan akses langsung.
Anda perlu memeriksa untuk melihat apakah sudah ada sebelum menambahkannya, atau jika Anda hanya perlu menunjukkan keberadaan, "menambahkan" lagi tidak benar-benar mengubah apa pun, itu hanya mengaturnya pada objek lagi.
sumber