HashMap JavaScript class for Node.js and the browser. The keys can be anything and won't be stringified

Overview

HashMap Class for JavaScript

Installation

NPM

Using npm:

$ npm install hashmap

Using bower:

$ bower install hashmap

You can download the last stable version from the releases page.

If you like risk, you can download the latest master version, it's usually stable.

To run the tests:

$ npm test

Description

This project provides a HashMap class that works both on Node.js and the browser. HashMap instances store key/value pairs allowing keys of any type.

Unlike regular objects, keys will not be stringified. For example numbers and strings won't be mixed, you can pass Date's, RegExp's, DOM Elements, anything! (even null and undefined)

HashMap constructor overloads

  • new HashMap() creates an empty hashmap
  • new HashMap(map:HashMap) creates a hashmap with the key-value pairs of map
  • new HashMap(arr:Array) creates a hashmap from the 2D key-value array arr, e.g. [['key1','val1'], ['key2','val2']]
  • new HashMap(key:*, value:*, key2:*, value2:*, ...) creates a hashmap with several key-value pairs

HashMap methods

  • get(key:*) : * returns the value stored for that key.
  • set(key:*, value:*) : HashMap stores a key-value pair
  • multi(key:*, value:*, key2:*, value2:*, ...) : HashMap stores several key-value pairs
  • copy(other:HashMap) : HashMap copies all key-value pairs from other to this instance
  • has(key:*) : Boolean returns whether a key is set on the hashmap
  • search(value:*) : * returns key under which given value is stored (null if not found)
  • delete(key:*) : HashMap deletes a key-value pair by key
  • remove(key:*) : HashMap Alias for delete(key:*) (deprecated)
  • type(key:*) : String returns the data type of the provided key (used internally)
  • keys() : Array<*> returns an array with all the registered keys
  • values() : Array<*> returns an array with all the values
  • entries() : Array<[*,*]> returns an array with [key,value] pairs
  • size : Number the amount of key-value pairs
  • count() : Number returns the amount of key-value pairs (deprecated)
  • clear() : HashMap deletes all the key-value pairs on the hashmap
  • clone() : HashMap creates a new hashmap with all the key-value pairs of the original
  • hash(key:*) : String returns the stringified version of a key (used internally)
  • forEach(function(value, key)) : HashMap iterates the pairs and calls the function for each one

Method chaining

All methods that don't return something, will return the HashMap instance to enable chaining.

Examples

Assume this for all examples below

var map = new HashMap();

If you're using this within Node, you first need to import the class

var HashMap = require('hashmap');

Basic use case

map.set("some_key", "some value");
map.get("some_key"); // --> "some value"

Map size / number of elements

var map = new HashMap();
map.set("key1", "val1");
map.set("key2", "val2");
map.size; // -> 2

Deleting key-value pairs

map.set("some_key", "some value");
map.delete("some_key");
map.get("some_key"); // --> undefined

No stringification

map.set("1", "string one");
map.set(1, "number one");
map.get("1"); // --> "string one"

A regular Object used as a map would yield "number one"

Objects as keys

var key = {};
var key2 = {};
map.set(key, 123);
map.set(key2, 321);
map.get(key); // --> 123

A regular Object used as a map would yield 321

Iterating

map.set(1, "test 1");
map.set(2, "test 2");
map.set(3, "test 3");

map.forEach(function(value, key) {
    console.log(key + " : " + value);
});
// ES6 Iterators version
for (const pair of map) {
    console.log(`${pair.key} : ${pair.value}`)
}

Method chaining

map
  .set(1, "test 1")
  .set(2, "test 2")
  .set(3, "test 3")
  .forEach(function(value, key) {
      console.log(key + " : " + value);
  });

LICENSE

The MIT License (MIT)

Copyright (c) 2012 Ariel Flesler

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF

To-Do

  • (?) Allow extending the hashing function in a AOP way or by passing a service
  • Make tests work on the browser
Comments
  • Collisions for distinct values are trivial to generate

    Collisions for distinct values are trivial to generate

    ... and thus not guaranteed to not happen accidentally e.g.:

    • [ "foo", "bar", "baz" ] -> '["foo|"bar|"baz'
    • [ "foo", 'bar|"baz' ] -> '["foo|"bar|"baz'

    A JSON-style representation would at least be unambiguous e.g. hash strings with JSON.stringify, arrays as [ *, ... ], and objects as { "...": *, ... } (with sorted keys) e.g.:

    • [ "foo", "bar", "baz" ] -> '["foo","bar","baz"]'
    • [ "foo", 'bar|"baz' ] -> '["foo","bar|\\"baz"]'

    See here for more details.

    enhancement 
    opened by chocolateboy 15
  • Added delete() as alias for remove() (ES6 map compatibility)

    Added delete() as alias for remove() (ES6 map compatibility)

    ES6 maps have a delete() instead of a remove() function, therefore I added delete() as an alias for remove(). No actually new code has been added, but I added a full unit test (copy of remove() unit test) anyway, just to be safe.

    Note that there is (as far as I know) no way to achieve 100% compatibility as Map.prototype.size is a number whereas HashMap.prototype.count is a function. My goal is to get the best compatibility possible without changing anything major in HashMap for now.

    opened by ulikoehler 14
  • Initializer argument in constructor

    Initializer argument in constructor

    It would be nice to be able to write an initializer/immediate with the constructor like this:

    new hashmap([
      [key, value],
      [key2, value2],
      etc
    ])
    
    enhancement 
    opened by fresheneesz 10
  • Implemented each()

    Implemented each()

    Hello, here's a simple approach to each() with tests and an example in the readme. You just pass it a function with key/value as args, and it'll be called for each pair in the hashmap. Got the job done for me...

    opened by devoncrouse 10
  • Fix for use strict

    Fix for use strict

    Inside the final else of the loader section of Hashmap is an innocuous error if 'use strict' is ever added.

    	} else {
    		// Browser globals (this is window)
    		this.HashMap = factory();
    	}
    

    With 'use strict' the IIFE actually has no this variable because it is not called via bind/apply. Clearly this was meant as the final fallback to load Hashmap into the global namespace (window) when neither requirejs or amd are used. In a non-strict environment it would do just that, this === window, but with strict we don't get that luxury.

    The code to discover "global" is from: https://github.com/purposeindustries/window-or-global/blob/master/lib/index.js Which technically finds either window/self (browser) or global (node).

    I only noticed this problem after running hashmap through a minifier, wherein it also added 'use struct'. I left my fix as optional as possible, so your code flow is unchanged unless this becomes falsey.

    I know you aren't using 'use struct' in the project, but it would make it simpler for others if they concat/minify and 'use struct' ever gets added in.

    opened by nicholi 8
  • Made count() an O(1) operation

    Made count() an O(1) operation

    Background story: I found myself in situation where I have to build nested hashmaps to keep track of relations between objects in my app. They form a tree-like structure . The tricky part is to know when to remove a leaf. I need to remove a nested hashmap from its parent once it becomes empty, so that parent can deallocate it (probably causing a cascade into its parent if it also becomes empty, etc.). One way to do this is to check if the hashmap is empty after each remove operation. The problem is that implementation of count() was linear, which effectively causes each removal a linear operation in my scenario.

    Solution: I see two ways of solving this. A) adding an explicit isEmpty() operation which "simply" checks if this._data is empty. This in turn is not obvious how to do in O(1) time, as this._data is a simple js object. Moreover this would add a new function to the interface, which is probably not a decision taken lightly. B) making count() work in O(1) time by maintaining the current this._count on each operation in O(1)

    I like the later solution better, and here is my attempt at it. This is my first pull request on github, so you are welcome to let me know if I did something wrong!

    opened by qbolec 7
  • Best way to sort by key or value?

    Best way to sort by key or value?

    Howdy -

    Any recommendations on the best way to sort these hashmaps by key or value?

    I've seen tuple-based approaches, basically breaking the hashmap into two distinct arrays, sorting by key or value and then recombining them into the hashmap.

    Just wondering whether there's some other pattern that I'm missing. Btw, thanks for the hashmap!

    opened by joereger 6
  • Wrong behaviour?

    Wrong behaviour?

    Hello,

    I've gone through your Readme and noticed the following issue:

    Objects as keys var key = {}; var key2 = {}; map.set(key, 123); map.set(key2, 321); map.get(key); // --> 123 A regular Object used as a map would yield 321

    Shouldn't map.get(key) return 321? Because hash(key) should be equal to hash(key2) here as far as both objects has the same set of properties (basically, both have no own properties and the only difference is different placement in memory). But in your example it behaves like it just compares references.

    opened by devlato 5
  • Not a hashmap

    Not a hashmap

    I just read the code, and you are literally just using a string as a key to an object property as your storage, your hash function doesn't even return a hash, it returns a string.

    Where are the buckets? Where is the correct hashing algorithm?

    opened by jackmoxley 4
  • Question: object as keys

    Question: object as keys

    [bad English] I have a project where i use class types for my objects. e.g. There is a UserId class wrapper that saves the id as a string UserId{value:string}

    The thing is that i create this userid multiple times. e.g when i retrieve the value from the db i create a new object with the string value i get from the db.Essentially i create a new UserId object.

    Based on how this library works,i cant i set my UserId class as a key to a hashmap because the hash is reset every time i create a new instance.

    the result i'm trying to achieve is let users:HashMap<UserId,User> = new HashMap<>(); users.set(new UserId("123"),user1);

    let userId:UserId = new UserId("123");

    let userIdSame:UserId = new UserId("123");

    users.get(userId); //expect to be user1 users.get(userIdSame); //expect to be user1

    Are there any plans to support such case? Thanks

    EDIT: Followup question: Shouldn't the hashing of an object depend only on the values of the instance? For example in Java two different instances with the same values, would have the same hashcode

    feature 
    opened by alator21 4
  • Could you elaborate on the runtimes of the operations, basically get, set, multi and has?

    Could you elaborate on the runtimes of the operations, basically get, set, multi and has?

    Hi, I'm curious to know the run-time of each of the operations, get, set, multi and has.

    I wouldn't mind knowing the runtimes of the other functions. But mainly these.

    question 
    opened by incorelabs 4
  • Clarify readme

    Clarify readme

    Please, clarify in the readme that it is impossible with this library to get the same value using another object as a key that is structurally identical to the first key object. Because this is what HashMap is usually used for. For example:

    const key1 = { k: 'v' }
    const key2 = { k: 'v' }
    map.set(key1, 'val1')
    map.set(key2, 'val2')
    // actual behavior is that key1 and key2 have different hashes, so:
    map.get(key1) // --> 'val1'
    map.get(key2) // --> 'val2'
    // expected behavior (same hashes):
    map.get(key1) // --> 'val2'
    map.get(key2) // --> 'val2'
    
    opened by ReFruity 0
  • 3.0.0 Switched to hashmap with performance improvements

    3.0.0 Switched to hashmap with performance improvements

    Switched to a hashmap trie. With significantly faster insertion rates, creating a new instance is slower, albeit that is likely to be done substantially less than modification of the map. There is potential to improve performance, especially around create. Let me know what you think.

    2.4.0 is 38.76 X faster on create an increase of 3775.95% 3.0.0 is 1.76 X faster on singleSet an increase of 76.11% 3.0.0 is 2.16 X faster on singleSet 20 an increase of 116.21% 3.0.0 is 1.91 X faster on singleReplace an increase of 90.53% 3.0.0 is 1.44 X faster on setAfter 1,024 an increase of 44.02% 3.0.0 is 1.91 X faster on set 20 After 1,024 an increase of 90.84% 3.0.0 is 3.25 X faster on setAfter 131'072 an increase of 225.36% 3.0.0 is 3.70 X faster on set 20 After 131'072 an increase of 270.20%

    opened by jackmoxley 4
Owner
Ariel Flesler
Senior Full Stack Engineer
Ariel Flesler
Immutable persistent data collections for Javascript which increase efficiency and simplicity.

Immutable collections for JavaScript Immutable data cannot be changed once created, leading to much simpler application development, no defensive copy

Immutable.js 32.4k Dec 31, 2022
ClojureScript's persistent data structures and supporting API from the comfort of vanilla JavaScript

mori A simple bridge to ClojureScript's persistent data structures and supporting APIs for vanilla JavaScript. Pull requests welcome. Breaking changes

David Nolen 3.4k Dec 31, 2022
A complete, fully tested and documented data structure library written in pure JavaScript.

Buckets A JavaScript Data Structure Library Buckets is a complete, fully tested and documented data structure library written in pure JavaScript. Incl

Mauricio 1.2k Jan 4, 2023
Immutable persistent data collections for Javascript which increase efficiency and simplicity.

Immutable collections for JavaScript Immutable data cannot be changed once created, leading to much simpler application development, no defensive copy

Immutable.js 32.4k Jan 7, 2023
An isomorphic and configurable javascript utility for objects deep cloning that supports circular references.

omniclone An isomorphic and configurable javascript function for object deep cloning. omniclone(source [, config, [, visitor]]); Example: const obj =

Andrea Simone Costa 184 May 5, 2022
Hjson for JavaScript

hjson-js Hjson, a user interface for JSON JSON is easy for humans to read and write... in theory. In practice JSON gives us plenty of opportunities to

Hjson 387 Dec 20, 2022
A GitHub Action to generate reports that contain all the SSH keys, personal access tokens, GitHub App installations, deploy keys and their respective permissions authorized against a GitHub organization.

A GitHub Action to generate reports that contain all the SSH keys, personal access tokens, GitHub App installations, deploy keys and their respective permissions authorized against a GitHub organization.

Nick Nagel 5 Dec 13, 2022
Notes may contain grammatical errors and some wont make sense and will only make sense to me

This is my own notes containing all the information and knowledge I've gained during my studying sessions. The notes are all topics that relates to technology such as computers, software or programming.

null 126 Dec 15, 2022
⚡️The Fullstack React Framework — built on Next.js

The Fullstack React Framework "Zero-API" Data Layer — Built on Next.js — Inspired by Ruby on Rails Read the Documentation “Zero-API” data layer lets y

⚡️Blitz 12.5k Jan 4, 2023
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Generate random ethereum wallets & private keys and then check if they match a wallet that contains some kind of balance, so that you can take it. In Node.js

Ethereum-Stealer Generate random ethereum wallets & private keys and then check if they match a wallet that contains some kind of balance, so that you

Michał 74 Dec 24, 2022
Want to preserve your loved one's voices for eternity? Narrate anything using the a voice imprint that can be made in as little as 10 minutes of audio samples. Easy as pie.

Want to preserve your loved one's voices for eternity? Narrate anything using the a voice imprint that can be made in as little as 10 minutes of audio samples. Easy as pie.

Ari 15 Nov 29, 2022
The node module that allows you to control your Ethereum revocation lists & resolve revocation keys.

Ethereum Revocation Registry Controller The controller module for interacting with EIP-5539-compatible Ethereum revocation lists. Motivation The EIP-5

spherity 4 Sep 27, 2022
Best in class web3 SDKs for Browser, Node and Mobile apps

thirdweb JavaScript/TypeScript monorepo Best in class web3 SDKs for Browser, Node and Mobile apps Packages Package Description Latest Version /sdk Bes

thirdweb 69 Jan 8, 2023
Send encrypted and decrypted messages with verifiable keys and human readable names.

zooko-msg Encrypt and decrypt messages using AES with a preshared ECDH key generated using keys associated with Handshake names. I noticed that there

Publius Federalist 31 Jul 27, 2022