CrazySynthax
CrazySynthax

Reputation: 15048

Node: how to put objects as keys of hash object?

Please look at the following code snippet:

class Node {
    constructor(num) {
        this.num = num;
        this.right = null;
        this.left = null;
    }
}

let node1 = new Node(1);
let node2 = new Node(2);
let hash = {};
hash[node1] = 1;
console.log(hash[node2]);  // prints "1" ????

Why does hash[node2] returns a value of 1? Only node1 was stored in the hash...

Upvotes: 1

Views: 598

Answers (3)

Alan Alright
Alan Alright

Reputation: 1

You can use Object.assign() method on your hash object like this:

hash = Object.assign({node1, node2}, {});

Upvotes: 0

Lee Brindley
Lee Brindley

Reputation: 6502

If you log your object you get this:

{ '[object Object]': 1 }

Hence why the below logs 1, as node2 is being interpreted as [object Object]

console.log(hash[node2]); //This is evaluating hash['object Object'] (Again)

To get around this, there are a number of approaches, one would be to stringify your object using the JSON API, and use the return value as the key.

E.g.

hash[JSON.stringify(node1)] = 1;

Now what you have is:

{'{"num":1,"right":null,"left":null}': 1 }

And thus, accessing hash[node2] will now be undefined, as expected.

hash[node2] === undefined; //true
hash[JSON.stringify(node2)] === undefined; //true

You would probably want to create a little API around this. As a very rough example:

class Hash {

    constructor () {
        this.hashes = {};
    }

    get (key) {
        return this.hashes[JSON.stringify(key)];
    }

    set (key, value) {
        this.hashes[JSON.stringify(key)] = value;
    }
}

const hashStore = new Hash();

hashStore.set({foo: 'bar'}, 1);

hashStore.set({foo: 'cheese'}, 2);

console.log(hashStore.get({foo: 'bar'})); // 1
console.log(hashStore.get({foo: 'cheese'})); //2

Alternatively, if you are only using objects as keys which are in 'your control', then as Jakub Keller points out in his answer, you could override the toString function of your Node class.

The fallback of both approaches here is 'uniqueness', for either method to be a stable approach, you would want to introduce a unique key for each object, if you go with Jakub Keller's approach, you'd use that unique key in the toString override.

Both approaches satisfy a set of needs, if you're storing literals, an array of different objects as your keys, i'd probably go with my approach, and have the API write a custom, unique ID onto each object stored in the get method, again not perfect, as you could overwrite an existing key.

Upvotes: 3

Jakub Keller
Jakub Keller

Reputation: 497

The value shows as 1 because the hash of either object is technically [object Object]. Therefore, your key is [object Object].

Try overriding the Node class's toString and explicitly converting it by calling toString:

class Node {
    constructor(num) {
        this.num = num;
        this.right = null;
        this.left = null;
    }

    toString() {
        return this.num;
    }
}

let node1 = new Node(1);
let node2 = new Node(2);
let hash = {};
hash[node1] = 1;
console.log(hash[node2.toString()]);
// output: 2

Upvotes: 2

Related Questions