Last active
January 21, 2021 14:21
-
-
Save codeserk/253b6b61cc689e40160fa3bb041bdb45 to your computer and use it in GitHub Desktop.
Design a hashmap without using any built-in libraries. You should include the following functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface MapItem<T> { | |
readonly key: string, | |
readonly value: T | |
} | |
/** HashMap implementation using a 2D array */ | |
class ArrayHashMap<T> { | |
/** | |
* Buckets where data will be stored | |
* | |
* <key hash % max> => [ <item1>, <item2>, ..., <itemN> ] | |
*/ | |
protected readonly buckets: MapItem<T>[][] = [] | |
/** | |
* Constructor. | |
* @param bucketSize Size of the array, greater means less collisions. | |
*/ | |
constructor(protected readonly bucketSize: number = 1000) {} | |
/** | |
* Gets a value from the map. | |
* @param key | |
* @returns value if found, -1 otherwise. | |
*/ | |
get(key: string): T | -1 { | |
const bucket = this.getBucket(key) | |
const item = bucket.find(item => item.key === key) | |
return item !== undefined ? item.value : -1 | |
} | |
/** | |
* Adds a new value to the map, replaces it if it existed. | |
* @param key | |
* @param value | |
*/ | |
put(key: string, value: T): void { | |
const bucket = this.getBucket(key) | |
for (const item of bucket) { | |
if (item.key === key) { | |
item.value = value | |
return | |
} | |
} | |
const index = this.getBucketIndex(key) | |
bucket.push({ key, value }) | |
this.buckets[index] = bucket | |
} | |
/** | |
* Removes a key from the map. | |
* @param key | |
*/ | |
remove(key: string): void { | |
const index = this.getBucketIndex(key) | |
const updatedBucket = this.getBucket(key).filter(item => item.key !== key) | |
this.buckets[index] = updatedBucket | |
} | |
/** | |
* Gets the bucket where the key should be present. | |
* @param key | |
* @returns bucket or empty array if the key is not present. | |
*/ | |
protected getBucket(key: string): MapItem<T>[] { | |
const index = this.getHash(key) % this.bucketSize | |
return this.buckets[index] || [] | |
} | |
/** | |
* Gets the bucket index from a key, ensures the index is not outside the | |
* boundaries of the array. (ha, as if that mattered at all here). | |
* @param key | |
* @returns index | |
*/ | |
protected getBucketIndex(key: string): number { | |
return this.getHash(key) % this.bucketSize | |
} | |
/** | |
* Gets a hash from a string, | |
* unsurprisingly, I took this from Stack-overflow (: | |
* @param key | |
* @returns numeric hash from a string | |
*/ | |
protected getHash(key: string): number { | |
return key.split('').reduce((result: number, char: string) => { | |
result = (result << 5) - result + char.charCodeAt(0) | |
return result & result | |
}, 0) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment