mapageKA21 mapageKA21 - 27 days ago 5
Javascript Question

Search for a value in nested objects

I have to check if an object contains a value in javascript and I don't know how to do it. The object looks like this:

Match {
player1: undefined,
player2: undefined,
childrenLeft:
Match {
player1: 'John',
player2: 'Mary',
childrenLeft: undefined,
childrenRight: undefined },
childrenRight:
Match {
player1: 'Michael',
player2: 'James',
childrenLeft: undefined,
childrenRight: undefined }
}


Now it's a competition with a final and two semi-finals but it could be much bigger depending on the number of players so I need to traverse all the tree.
I have this function that supposes to return the next opponent but it doesn't work when I search for players on the childrenLeft. So, when I execute Match.nextOpponent(James) I got 'Michael' as a result but when I execute Match.nextOpponent(Mary) I got 'undefined'.

Match.prototype.nextOpponent = function (player) {
if (this.player1 === player) return this.player2;
if (this.player2 === player) return this.player1;
if (!this.player2 && !this.player1 && this.childrenRight !== undefined) return this.childrenRight.nextOpponent(player);
if (!this.player1 && !this.player2 && this.childrenLeft !== undefined) return this.childrenLeft.nextOpponent(player);
}


Anyone could help?
Thank you so much

Answer

The problem occurs because you return in the last two if blocks, even when the return value from the recursive call is undefined. This means that if the first if condition is true, there is no way that the second if condition is even tried.

So to resolve this, use this code:

Match.prototype.nextOpponent = function (player) {
    if (this.player1 === player) return this.player2;
    if (this.player2 === player) return this.player1;
    var match;
    if (!this.player2 && !this.player1 && this.childrenRight) 
        match = this.childrenRight.nextOpponent(player);
    // maybe previous return value was undefined, then try the other side:
    if (!match && !this.player1 && !this.player2 && this.childrenLeft) 
        match = this.childrenLeft.nextOpponent(player);
    return match;
}

function Match(p1, p2) {
    this.player1 = p1;
    this.player2 = p2;
    this.childrenLeft = undefined;
    this.childrenRight = undefined;
}

Match.prototype.nextOpponent = function (player) {
    if (this.player1 === player) return this.player2;
    if (this.player2 === player) return this.player1;
    var match;
    if (!this.player2 && !this.player1 && this.childrenRight) 
        match = this.childrenRight.nextOpponent(player);
    if (!match && !this.player1 && !this.player2 && this.childrenLeft) 
        match = this.childrenLeft.nextOpponent(player);
    return match;
}

var root = new Match();
root.childrenLeft = new Match('John', 'Mary'); 
root.childrenRight = new Match('Michael', 'James'); 

console.log('James plays: ', root.nextOpponent('James'));
console.log('Mary plays: ', root.nextOpponent('Mary'));

NB: you don't have to compare childrenLeft with undefined. As undefined is falsy and any object is truthy, you can just evaluate childrenLeft in the if condition.