Home > Mobile >  Is there a way to effectively use Map/Set in TypeScript/JavaScript with objects?
Is there a way to effectively use Map/Set in TypeScript/JavaScript with objects?

Time:12-09

I am learning TypeScript with a background in Java, where I am used to being able to easily work with hashmaps and hashsets with objects by overriding the hashCode method. Is there a way to do a similar thing in TypeScript?

class Coord {
    x: number;
    y: number;
    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }

    toString(): string {
        return ((this.x   this.y) * (this.x   this.y   1)/2).toString();
    }

    hashCode(): number {
        return (this.x   this.y) * (this.x   this.y   1)/2;
    }
}

const f = () => {
    let visited: Set<Coord> = new Set();
    visited.add(new Coord(1, 1));
    visited.add(new Coord(1, 1));
    console.log(visited.size)
}

f()

I have tried modifying toString and hashCode, but I still get that visited.size is 2.

CodePudding user response:

Sets and Maps use the SameValueNonNumber logic to determine unique objects in the Set and unique keys in the Map. This means that object references are compared, and there is no deep object inspection.

There is no equivalent of Java's Object.hashCode to override this logic.

To provide equivalent functionality, you will need to write your own version of Set that will use hashCode():

class Coord {
  constructor(x, y) { this.x = x; this.y = y; }
  toString() { return ((this.x   this.y) * (this.x   this.y   1)/2).toString(); }
  hashCode() { return (this.x   this.y) * (this.x   this.y   1)/2; }
}

class HashCodeSet {
  constructor() { this.map = new Map(); }
  add(x)        { this.map.set(x.hashCode(), x); }
  values(x)     { return this.map.values(); }
  has(x)        { return this.map.has(x.hashCode()); }
  delete(x)     { return this.map.delete(x.hashCode()); }
  clear()       { this.map.clear(); }
  get size()    { return this.map.size; }
}

const f = () => {
  let set = new HashCodeSet();
  set.add(new Coord(1, 1));
  set.add(new Coord(1, 1));
  console.log(set.size); // 1
}

f();

CodePudding user response:

You can't get around the fact that Set's will use strict equality === style key comparisons.

But you can do it yourself pretty easily.

Here's an option in Typescript:

type Hashable = { hashCode(): number }

class HashSet<T extends Hashable> {
    #map: Map<number, T> = new Map()

    add(item: T): void {
        if (!this.has(item)) {
            this.#map.set(item.hashCode(), item)
        }
    }

    has(item: T): boolean {
        return this.#map.has(item.hashCode())
    }

    delete(item: T): void {
        this.#map.delete(item.hashCode())
    }

    get size(): number {
        return this.#map.size
    }
}

See Playground

  • Related