user1203497
user1203497

Reputation: 517

In Node.js/Javascript, how to check if value exists in multidimensional array?

Lets say I have array something like this:

$game = Array
(
    ['round'] => Array
        (
            ['match'] => Array
                (
                    ['player_2'] => Array
                        (
                            [name] => asddd
                            [id] => 1846845
                            [winner] => yes
                        )

                    ['player_21'] => Array
                        (
                            [name] => ddd
                            [id] => 1848280
                            [winner] => no
                        )

                )
        )
)

And lets say in Node.js/Javascript I need to check if player_3 winner key value is yes. In PHP, you did something like this:

if( $game['round']['match'][player_3]['winner'] == 'yes'){

}

Because there is no player_3 it returns false in PHP, but if I did something similar in Javascript:

 if( typeof game['round']['match'][player_3]['winner'] != 'undefined' && game['round']['match'][player_3]['winner'] == 'yes'){

 }

I would get error: (node:15048) UnhandledPromiseRejectionWarning: TypeError: Cannot read property '0' of undefined, because player_3 doesn't exist in array and you can't check key value of array, that doesn't exist.

You could do this in Javascript:

if( 
   typeof game['round'] != 'undefined' &&
   typeof game['round']['match'] != 'undefined' &&
   typeof game['round']['match']['player_3'] != 'undefined' &&
   typeof game['round']['match']['player_3']['winner'] != 'undefined' &&
   typeof game['round']['match']['player_3']['winner'] == 'yes'
){
   var playerIsWinner = true;
}else{
   var playerIsWinner = false;
}

You check each array inside array from top down and make sure that they exists. I don't know if it actually works, but even if it does, it seems bad and stupid way to check something. I mean look how simple it is in PHP, while in Javascript I have to check each array existence inside array. So is there better way checking value of array?

Upvotes: 4

Views: 3466

Answers (5)

Artem
Artem

Reputation: 2047

Please, look at the lodash library, especially at methods, such as get. Then you may safely try something like:

_.get(game, 'round.match.player3.winner', false);

That's it :)

Upvotes: 2

A l w a y s S u n n y
A l w a y s S u n n y

Reputation: 38532

No you don't need to do manual check for deeply nested data for null or undefined, instead you could rollout your own small but compact function in this case get and be flexible with any input data provided. See more about Array.prototype.reduce()

// this single line will do the trick
const get = (p, o) =>p.reduce((xs, x) => (xs && xs[x]) ? xs[x] : null, o)

// let's pass in our props object...

const props = {"round":{"match":[{"player_21":{"name":"asdfg","id":1846845,"winner":"not yet"}},{"player_2":{"name":"sany","id":1846280,"winner":"no"}},{"player_3":{"name":"sunny","id":1846000,"winner":"yes"}}]}}

var playerIsWinner = false;
//console.log(get(['round', 'match', 2, 'player_3', 'winner'], props))
if (get(['round', 'match', 2, 'player_3', 'winner'], props) == 'yes') {
  playerIsWinner = true;
}

console.log(playerIsWinner)

Upvotes: 1

Patryk Cieszkowski
Patryk Cieszkowski

Reputation: 751

The array you've shown resembles more of an object in JS. So here's what you could possibly try.

const obj = {
  round: {
    match: {
      player_2: {
        name: 'asddd',
        id: 1846845,
        winner: true
      },
      player_21: {
        name: 'ddd',
        id: 1848280,
        winner: false
      }
    }
  }
}

...

const isWinner = (key) => {
  try {
    return obj.round.match[key].winner
  } catch(e) {
    return false
  }
}


console.log(isWinner('player_2'))

By wrapping your return inside of try ... catch, you prevent the error from being thrown at your query and possibly stopping the app from continuing on. If from whatever reason the structure of your object would change, you'd still have a boolean value returned.

If you have to keep your winner value in form of a string, you could simply compare the value, and you'll end up with boolean as a result. As so:

const isWinner = (key) => {
  try {
    return (obj.round.matchs[key].winner === 'yes')
  } catch(e) {
    return false
  }
}

Upvotes: 1

Willem van der Veen
Willem van der Veen

Reputation: 36630

Just wrap in a try catch block. This allows you to skip all of your boilerplate typeof statements:

   typeof game['round'] != 'undefined' &&
   typeof game['round']['match'] != 'undefined' &&
   typeof game['round']['match']['player_3'] != 'undefined' &&
   typeof game['round']['match']['player_3']['winner'] != 'undefined' &&
   typeof game['round']['match']['player_3']['winner'] == 'yes'

Instead throw an error and handle it if a element is not present. For example:

let nestedObj = {
  prop1: {
    propa1: {
      propb1: 'test'
    }
  },
  prop2: {}
}

try {
  console.log(nestedObj['prop1']['propa1']['propb1']);
  console.log(nestedObj['prop2']['propa2']['propb2']);
} catch(e) {
  console.log('prop not defined');
}

This is a lot simpler than checking for every simple condition like you are doing now.

Upvotes: 0

dikuw
dikuw

Reputation: 1158

You can do the following to avoid the undefined error:

 if ( game['round']['match'][player_3] && game['round']['match'][player_3]['winner'] == 'yes' ) {
   ...
 }

Because undefined is "falsey" you'll get false instead of undefined if player_3 does not exist, and true if player_3 exists and is the winner.

Upvotes: 0

Related Questions