Skip to content

Instantly share code, notes, and snippets.

@YannRobert
Last active October 2, 2024 11:13
Show Gist options
  • Save YannRobert/335a5dc5f2cb42575f352eac5a32dc86 to your computer and use it in GitHub Desktop.
Save YannRobert/335a5dc5f2cb42575f352eac5a32dc86 to your computer and use it in GitHub Desktop.
class User {
constructor(public name: string, public age: number, public city: string) {}
hashCode(): number {
let hash = 17;
hash = hash * 31 + this.name.hashCode();
hash = hash * 31 + this.age;
hash = hash * 31 + this.city.hashCode();
return hash;
}
equals(other: any): boolean {
if (!(other instanceof User)) return false;
return this.name === other.name &&
this.age === other.age &&
this.city === other.city;
}
toString(): string {
return `User(${this.name}, ${this.age}, ${this.city})`;
}
}
// Example usage:
const userSet = new HashSet<User>();
const user1 = new User("Alice", 30, "New York");
const user2 = new User("Bob", 25, "Los Angeles");
const user3 = new User("Charlie", 35, "Chicago");
const user4 = new User("Alice", 30, "New York"); // Same as user1
console.log(userSet.add(user1)); // Output: true
console.log(userSet.add(user2)); // Output: true
console.log(userSet.add(user3)); // Output: true
console.log(userSet.add(user4)); // Output: false (already exists)
console.log(userSet.size()); // Output: 3
console.log(userSet.has(user1)); // Output: true
console.log(userSet.has(new User("Alice", 30, "New York"))); // Output: true (equal to user1)
userSet.delete(user2);
console.log(userSet.size()); // Output: 2
console.log("Users in the set:");
for (const user of userSet) {
console.log(user.toString());
}
// Convert to array and print
console.log("Users as array:", userSet.toArray().map(user => user.toString()));
class HashSet<T> {
private map: HashMap<T, boolean>;
constructor() {
this.map = new HashMap<T, boolean>();
}
add(value: T): boolean {
if (this.map.has(value)) {
return false; // Value already exists
}
this.map.set(value, true);
return true;
}
delete(value: T): boolean {
return this.map.delete(value);
}
has(value: T): boolean {
return this.map.has(value);
}
clear(): void {
this.map.clear();
}
size(): number {
return this.map.getSize();
}
// Implement iterable interface
*[Symbol.iterator](): Iterator<T> {
for (const entry of this.map) {
yield entry[0]; // yield the key (value in the set)
}
}
// Optional: Add a method to convert the set to an array
toArray(): T[] {
return Array.from(this);
}
}
// Extend the String prototype with Java-like hashCode and equals methods
interface String {
hashCode(): number;
equals(other: any): boolean;
}
String.prototype.hashCode = function(): number {
let hash = 0;
for (let i = 0; i < this.length; i++) {
const char = this.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32-bit integer
}
return hash;
};
String.prototype.equals = function(other: any): boolean {
if (typeof other !== 'string') return false;
return this === other;
};
type Primitive = string | number | boolean | null | undefined;
function isPrimitive(value: any): value is Primitive {
return (
typeof value === "string" ||
typeof value === "number" ||
typeof value === "boolean" ||
value === null ||
value === undefined
);
}
function defaultHashCode(value: any): number {
if (typeof value === "string") {
return value.hashCode();
}
if (typeof value === "number") return value;
if (typeof value === "boolean") return value ? 1 : 0;
if (value === null) return 0;
if (value === undefined) return -1;
if (typeof value === "object" && "hashCode" in value && typeof value.hashCode === "function") {
return value.hashCode();
}
// For objects without a hashCode method, use a simple implementation
return JSON.stringify(value).split("").reduce((acc, char) => (acc * 31 + char.charCodeAt(0)) | 0, 0);
}
function defaultEquals(a: any, b: any): boolean {
if (a === b) return true;
if (typeof a === "string" && typeof b === "string") return a.equals(b);
if (isPrimitive(a) || isPrimitive(b)) return a === b;
if (a && typeof a === "object" && "equals" in a && typeof a.equals === "function") {
return a.equals(b);
}
return JSON.stringify(a) === JSON.stringify(b);
}
class Entry<K, V> {
constructor(public key: K, public value: V, public next: Entry<K, V> | null = null) {}
}
class HashMap<K, V> {
private buckets: Array<Entry<K, V> | null>;
private size: number;
private readonly INITIAL_CAPACITY = 16;
private readonly LOAD_FACTOR = 0.75;
constructor() {
this.buckets = new Array(this.INITIAL_CAPACITY).fill(null);
this.size = 0;
}
private getBucketIndex(key: K): number {
const hash = defaultHashCode(key);
return Math.abs(hash) % this.buckets.length;
}
set(key: K, value: V): void {
if (this.size >= this.LOAD_FACTOR * this.buckets.length) {
this.resize();
}
const index = this.getBucketIndex(key);
let entry = this.buckets[index];
while (entry !== null) {
if (defaultEquals(entry.key, key)) {
entry.value = value;
return;
}
entry = entry.next;
}
const newEntry = new Entry(key, value, this.buckets[index]);
this.buckets[index] = newEntry;
this.size++;
}
get(key: K): V | undefined {
const index = this.getBucketIndex(key);
let entry = this.buckets[index];
while (entry !== null) {
if (defaultEquals(entry.key, key)) {
return entry.value;
}
entry = entry.next;
}
return undefined;
}
delete(key: K): boolean {
const index = this.getBucketIndex(key);
let entry = this.buckets[index];
let prev: Entry<K, V> | null = null;
while (entry !== null) {
if (defaultEquals(entry.key, key)) {
if (prev === null) {
this.buckets[index] = entry.next;
} else {
prev.next = entry.next;
}
this.size--;
return true;
}
prev = entry;
entry = entry.next;
}
return false;
}
has(key: K): boolean {
return this.get(key) !== undefined;
}
clear(): void {
this.buckets = new Array(this.INITIAL_CAPACITY).fill(null);
this.size = 0;
}
getSize(): number {
return this.size;
}
private resize(): void {
const oldBuckets = this.buckets;
this.buckets = new Array(this.buckets.length * 2).fill(null);
this.size = 0;
for (const bucket of oldBuckets) {
let entry = bucket;
while (entry !== null) {
this.set(entry.key, entry.value);
entry = entry.next;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment