Sebagaimana dijelaskan dalam pembaruan 3 pada jawaban ini, notasi ini:
var hash = {};
hash[X]
sebenarnya tidak hash objek X
; sebenarnya hanya mengkonversi X
ke string (melalui .toString()
apakah itu objek, atau beberapa konversi bawaan untuk berbagai jenis primitif) dan kemudian melihat string itu, tanpa hashing, di " hash
". Kesetaraan objek juga tidak dicentang - jika dua objek yang berbeda memiliki konversi string yang sama, mereka hanya akan saling menimpa.
Dengan ini - apakah ada implementasi hashmaps yang efisien dalam javascript? (Misalnya, hasil Google ke-2 javascript hashmap
menghasilkan implementasi yang O (n) untuk operasi apa pun. Berbagai hasil lainnya mengabaikan fakta bahwa objek yang berbeda dengan representasi string setara menimpa satu sama lain.
Jawaban:
Mengapa tidak hash objek Anda sendiri secara manual, dan gunakan string yang dihasilkan sebagai kunci untuk kamus JavaScript biasa? Bagaimanapun, Anda berada dalam posisi terbaik untuk mengetahui apa yang membuat objek Anda unik. Itu yang saya lakukan.
Contoh:
Dengan cara ini Anda dapat mengontrol pengindeksan yang dilakukan oleh JavaScript tanpa mengangkat alokasi memori, dan penanganan overflow.
Tentu saja, jika Anda benar-benar menginginkan "solusi tingkat industri", Anda dapat membangun kelas yang diparameterisasi oleh fungsi utama, dan dengan semua API yang diperlukan dari wadah, tapi ... kami menggunakan JavaScript, dan berusaha menjadi sederhana dan ringan, jadi solusi fungsional ini sederhana dan cepat.
Fungsi kunci dapat sesederhana memilih atribut yang tepat dari objek, misalnya, kunci, atau seperangkat kunci, yang sudah unik, kombinasi kunci, yang unik bersama-sama, atau serumit menggunakan beberapa hash kriptografi seperti dalam DojoX Encoding , atau DojoX UUID . Sementara solusi terakhir dapat menghasilkan kunci unik, secara pribadi saya mencoba menghindarinya dengan segala cara, terutama, jika saya tahu apa yang membuat objek saya unik.
Pembaruan pada tahun 2014: Dijawab pada tahun 2008 solusi sederhana ini masih membutuhkan lebih banyak penjelasan. Izinkan saya mengklarifikasi ide dalam bentuk tanya jawab.
Solusi Anda tidak memiliki hash nyata. Dimana itu???
JavaScript adalah bahasa tingkat tinggi. Primitif dasarnya ( Object ) termasuk tabel hash untuk menyimpan properti. Tabel hash ini biasanya ditulis dalam bahasa tingkat rendah untuk efisiensi. Menggunakan objek sederhana dengan kunci string, kami menggunakan tabel hash yang diimplementasikan secara efisien tanpa upaya dari pihak kami.
Bagaimana Anda tahu mereka menggunakan hash?
Ada tiga cara utama untuk menjaga koleksi objek tetap dialamatkan oleh kunci:
Jelas objek JavaScript menggunakan tabel hash dalam beberapa bentuk untuk menangani kasus umum.
Apakah vendor browser benar-benar menggunakan tabel hash ???
Betulkah.
Apakah mereka menangani tabrakan?
Iya. Lihat di atas. Jika Anda menemukan tabrakan pada string yang tidak setara, jangan ragu untuk mengajukan bug ke vendor.
Jadi apa idemu?
Jika Anda ingin meng-hash suatu objek, temukan apa yang membuatnya unik dan gunakan sebagai kunci. Jangan mencoba menghitung hash asli atau meniru hash tables - itu sudah ditangani secara efisien oleh objek JavaScript yang mendasarinya.
Gunakan kunci ini dengan JavaScript
Object
untuk memanfaatkan tabel hash bawaan sambil menghindari kemungkinan bentrokan dengan properti default.Contoh untuk Anda mulai:
Saya menggunakan saran Anda dan cache semua objek menggunakan nama pengguna. Tetapi beberapa orang bijak bernama "toString", yang merupakan properti bawaan! Apa yang harus saya lakukan sekarang?
Jelas, jika bahkan memungkinkan bahwa kunci yang dihasilkan secara eksklusif terdiri dari karakter Latin, Anda harus melakukan sesuatu. Misalnya, tambahkan karakter Unicode non-Latin yang Anda sukai di awal atau di akhir untuk tidak berbenturan dengan properti default: "#toString", "#MarySmith". Jika kunci komposit digunakan, pisahkan komponen kunci menggunakan semacam pembatas non-Latin: "nama, kota, negara".
Secara umum ini adalah tempat, di mana kita harus kreatif, dan memilih kunci termudah dengan batasan yang diberikan (keunikan, potensi bentrokan dengan properti default).
Catatan: kunci unik tidak berbenturan dengan definisi, sementara potensi bentrokan hash akan ditangani oleh yang mendasarinya
Object
.Mengapa Anda tidak menyukai solusi industri?
IMHO, kode terbaik adalah tidak ada kode sama sekali: ia tidak memiliki kesalahan, tidak memerlukan pemeliharaan, mudah dimengerti, dan dijalankan secara instan. Semua "tabel hash dalam JavaScript" yang saya lihat adalah> 100 baris kode, dan melibatkan beberapa objek. Bandingkan dengan:
dict[key] = value
.Poin lain: apakah mungkin untuk mengalahkan kinerja objek primordial yang ditulis dalam bahasa tingkat rendah, menggunakan JavaScript dan objek primordial yang sama untuk mengimplementasikan apa yang sudah diterapkan?
Saya masih ingin hash objek saya tanpa kunci apa pun!
Kami beruntung: ECMAScript 6 (dijadwalkan untuk rilis pertengahan 2015, memberi atau mengambil 1-2 tahun setelah itu menjadi luas) mendefinisikan peta dan set .
Dilihat oleh definisi mereka dapat menggunakan alamat objek sebagai kunci, yang membuat objek langsung berbeda tanpa kunci buatan. OTOH, dua objek berbeda, namun identik, akan dipetakan sebagai berbeda.
Rincian perbandingan dari MDN :
sumber
Deskripsi masalah
JavaScript tidak memiliki tipe peta umum bawaan (kadang-kadang disebut array asosiatif atau kamus ) yang memungkinkan untuk mengakses nilai arbitrer dengan kunci arbitrer. Struktur data fundamental JavaScript adalah objek , tipe peta khusus yang hanya menerima string sebagai kunci dan memiliki semantik khusus seperti warisan prototipe, pengambil dan setter dan beberapa voodoo lebih lanjut.
Saat menggunakan objek sebagai peta, Anda harus ingat bahwa kunci akan dikonversi ke nilai string melalui
toString()
, yang menghasilkan pemetaan5
dan'5'
ke nilai yang sama dan semua objek yang tidak menimpatoString()
metode ke nilai yang diindeks oleh'[object Object]'
. Anda mungkin juga secara tidak sadar mengakses properti warisannya jika Anda tidak memeriksanyahasOwnProperty()
.Built-in JavaScript untuk berbagai jenis tidak membantu satu bit: array JavaScript tidak array asosiatif, tetapi hanya objek dengan beberapa sifat istimewa. Jika Anda ingin tahu mengapa mereka tidak dapat digunakan sebagai peta, lihat di sini .
Solusi Eugene
Eugene Lazutkin sudah menggambarkan ide dasar menggunakan fungsi hash khusus untuk menghasilkan string unik yang dapat digunakan untuk mencari nilai terkait sebagai properti dari objek kamus. Ini kemungkinan besar akan menjadi solusi tercepat, karena objek diimplementasikan secara internal sebagai tabel hash .
Untuk mendapatkan nilai hash unik untuk objek arbitrer, satu kemungkinan adalah dengan menggunakan penghitung global dan cache nilai hash di objek itu sendiri (misalnya dalam properti bernama
__hash
).Fungsi hash yang melakukan ini dan berfungsi untuk nilai dan objek primitif adalah:
Fungsi ini dapat digunakan seperti yang dijelaskan oleh Eugene. Untuk kenyamanan, kami akan membungkusnya dalam
Map
kelas.Map
Implementasi sayaImplementasi berikut ini juga akan menyimpan pasangan kunci-nilai dalam daftar yang tertaut ganda untuk memungkinkan pengulangan yang cepat atas kunci dan nilai. Untuk menyediakan fungsi hash Anda sendiri, Anda bisa menimpa metode instance
hash()
setelah pembuatan.Contoh
Script berikut
menghasilkan output ini:
Pertimbangan lebih lanjut
PEZ menyarankan untuk menimpa
toString()
metode ini, mungkin dengan fungsi hash kami. Ini tidak layak karena tidak bekerja untuk nilai-nilai primitif (perubahantoString()
untuk primitif adalah ide yang sangat buruk). Jika kita ingintoString()
mengembalikan nilai yang berarti untuk objek arbitrer, kita harus memodifikasiObject.prototype
, yang beberapa orang (termasuk saya sendiri) mempertimbangkan verboten .Sunting: Versi
Map
implementasi saya saat ini dan juga barang JavaScript lainnya dapat diperoleh dari sini .sumber
Map._counter = 0
, dan di konstruktor Peta lakukanthis._hash = 'object ' + Map._counter++
. Kemudian hash () menjadireturn (value && value._hash) || (typeof(value) + ' ' + String(value));
Saya tahu pertanyaan ini cukup lama, tetapi ada beberapa solusi yang sangat bagus saat ini dengan perpustakaan eksternal.
JavaScript juga memiliki bahasa yang disediakan
Map
.sumber
Berikut ini cara mudah dan nyaman menggunakan sesuatu yang mirip dengan peta java:
Dan untuk mendapatkan nilai:
sumber
Menurut ECMAScript 2015 (ES6) javascript standar memiliki implementasi Peta. Lebih banyak tentang yang dapat ditemukan di sini
Penggunaan dasar:
sumber
Anda dapat menggunakan ES6
WeakMap
atauMap
:Sadarilah bahwa tidak ada yang didukung secara luas, tetapi Anda dapat menggunakan ES6 Shim (memerlukan ES5 asli atau ES5 Shim ) untuk mendukung
Map
, tetapi tidakWeakMap
( lihat alasannya ).sumber
Anda harus menyimpan dalam beberapa bait keadaan internal pasangan objek / nilai
Dan gunakan seperti itu:
Tentu saja, implementasi ini juga di suatu tempat di sepanjang garis O (n). Contoh-contoh Eugene di atas adalah satu-satunya cara untuk mendapatkan hash yang bekerja dengan kecepatan apa pun yang Anda harapkan dari hash nyata.
Memperbarui:
Pendekatan lain, di sepanjang garis jawaban Eugene adalah entah bagaimana melampirkan ID unik untuk semua objek. Salah satu pendekatan favorit saya adalah mengambil salah satu metode bawaan yang diwarisi dari superclass Object, menggantinya dengan fungsi kustom passthrough dan melampirkan properti ke objek fungsi tersebut. Jika Anda menulis ulang metode HashMap saya untuk melakukan ini, akan terlihat seperti:
Versi ini tampaknya hanya sedikit lebih cepat, tetapi secara teori itu akan secara signifikan lebih cepat untuk set data yang besar.
sumber
Sayangnya, tidak ada jawaban di atas yang baik untuk kasus saya: objek kunci yang berbeda mungkin memiliki kode hash yang sama. Oleh karena itu, saya menulis versi HashMap sederhana seperti Java:
Catatan: objek kunci harus "mengimplementasikan" kode hashCode () dan equals ().
sumber
new Array()
lebih[]
adalah untuk memastikan Jawa-kemiripan mutlak kode Anda? :)Saya telah mengimplementasikan JavaScript HashMap yang kodenya dapat diperoleh dari http://github.com/lambder/HashMapJS/tree/master
Ini kodenya:
sumber
HashMap
s.Di ECMA6 Anda dapat menggunakan WeakMap
Contoh:
Tapi:
sumber
Javascript tidak membangun Map / hashmap. Itu harus disebut array asosiatif .
hash["X"]
sama denganhash.X
, tetapi izinkan "X" sebagai variabel string. Dengan kata lain,hash[x]
secara fungsional sama denganeval("hash."+x.toString())
Ini lebih mirip sebagai object.properties daripada pemetaan kunci-nilai. Jika Anda mencari pemetaan Kunci / nilai yang lebih baik dalam Javascript, silakan gunakan objek Peta yang dapat Anda temukan di web.
sumber
Coba implementasi tabel hash JavaScript saya: http://www.timdown.co.uk/jshashtable
Itu mencari metode hashCode () objek kunci, atau Anda dapat menyediakan fungsi hashing saat membuat objek Hashtable.
sumber
Ini terlihat seperti solusi yang cukup kuat: https://github.com/flesler/hashmap . Ia bahkan akan bekerja dengan baik untuk fungsi dan objek yang terlihat identik. Satu-satunya peretas yang digunakannya adalah menambahkan anggota yang tidak dikenal ke objek untuk mengidentifikasinya. Jika program Anda tidak menimpa variabel tidak jelas itu (seperti hashid ), berarti Anda berwarna emas.
sumber
Jika kinerja tidak kritis (misalnya jumlah tombol relatif kecil) dan Anda tidak ingin mencemari Anda (atau mungkin tidak Anda) objek dengan bidang tambahan seperti
_hash
,_id
, dll, maka Anda dapat menggunakan fakta bahwaArray.prototype.indexOf
mempekerjakan kesetaraan yang ketat. Berikut ini adalah implementasi sederhana:Contoh penggunaan:
Dibandingkan dengan ES6 WeakMap, ia memiliki dua masalah: O (n) waktu pencarian dan non-kelemahan (yaitu akan menyebabkan kebocoran memori jika Anda tidak menggunakan
delete
atauclear
melepaskan kunci).sumber
Implementasi My Map, berasal dari contoh Christoph:
Contoh penggunaan:
sumber
Menambahkan solusi lain:
HashMap
kelas pertama yang saya porting dari Jawa ke Javascript. Bisa dibilang ada banyak overhead, tetapi implementasinya hampir 100% sama dengan implementasi Java dan mencakup semua antarmuka dan subkelas.Proyek ini dapat ditemukan di sini: https://github.com/Airblader/jsava Saya juga akan melampirkan kode sumber (saat ini) untuk kelas HashMap, tetapi sebagaimana dinyatakan juga tergantung pada kelas super dll. Kerangka kerja OOP yang digunakan adalah qooxdoo.
Sunting: Harap dicatat bahwa kode ini sudah kedaluwarsa dan merujuk ke proyek github untuk pekerjaan saat ini. Saat penulisan ini, ada juga
ArrayList
implementasi.sumber
Namun implementasi peta lain oleh saya. Dengan pengacak, 'generik' dan 'iterator' =)
Contoh:
sumber