Gajus
Gajus

Reputation: 73908

Check if array[4][3][7][3] is defined

When there is a single dimension array, it is easy to check whether it is defined, by either simple calling arr[6] which will return undefined if such property does not exist or calling typeof arr[6] === undefined.

The problem is, that in my case I have arr[5][1][6][2][5][3][7], where arr[5] can be non existent, or arr[5][1], etc. Which will naturally trigger error: TypeError: Cannot read property [..] One solution is to write many IF statements. However, is there any better solution, that'd simple allow me to check whether arr[5][1][6][2][5][3][7] is defined?

Upvotes: 0

Views: 648

Answers (6)

JonnyReeves
JonnyReeves

Reputation: 6209

A pragmatic approach would be to break this problem down into its component parts; look at what data is known and the tools you have at hand.

So, what do we know - well we know the keys that we want to inspect, in the case of checking if arr[5][1][6][2][5][3][7] is defined. Now ask yourself, what tools do we have in JavaScript? To check if an Array index is defined we can compare against null, ie:

if (array[index] === null) { 
    return false 
}

If we were to try and write this code, one of the first things that should come to mind is to simply walk through each key, in order: eg:

if (array[5] === null) {
    return false;
} else if (array[5][1] === null) {
    return false
} ...snip...

// Good news, it's defined!
return true

Obviously this approach can be improved, it requires a tonne of duplicated code to be written out, it's inflexible and not reusable. If you ever find yourself doing the same thing over and over, you probably have a good candidate for a loop construct. In order for a loop you need a variant, something that will change with each repetition - in the example above the variant is the right most element of the nested array we are inspecting. First, let's start by listing our variants out:

var variants = [ 5, 1, 6, 2, 5, 3, 7 ];
for (var i = 0; i < variants.length; i++) {
   console.log("variant: " + variants[i]);
}

Where, do we go from here? Well things get a bit harder, you need to understand how Arrays are passed by reference in JavaScript and exploit that in the loop body; ultimately you may end up with something like this:

function arrayDimensionsExist(source, dimensions) {
    var currentDepth = source;
    for (var i = 0; i < dimensions.length; i++) {
        var key = dimensions[i];
        if (currentDepth[key] === null) {
            return false;
        } else {
            currentDepth = source[key];
        }
    }
    return true;
}

Upvotes: 1

PyKing
PyKing

Reputation: 2607

By using a try/catch block you can check if the element can be accessed.

var x;
try {
   x = arr[5][1][6][2][5][3][7];
} catch(TypeError)
{
   // the element cannot be accessed
   x = undefined;
}

Then it's easy enough to check if 'x' is defined or not using an if statement.

Upvotes: 1

There's no solution built-in to the language, but you could handle it with a function like this:

var verifyIndexes = function(target) {
    var current = target;
    for (i = 1; i < arguments.length; i++) {
        if (arguments[i] in current) {
            current = current[arguments[i]];
        } else {
            return false;
        }
    }
    return true;
}

var myArray = [[[1, 2, 3], 4], 5];
console.log(verifyIndexes(myArray, 0));        // true
console.log(verifyIndexes(myArray, 0, 0, 0));  // true
console.log(verifyIndexes(myArray, 0, 0, 3));  // false
console.log(verifyIndexes(myArray, 0, 1));     // true
console.log(verifyIndexes(myArray, 0, 2));     // false

Upvotes: 0

Jani Hartikainen
Jani Hartikainen

Reputation: 43253

Since this seemed like an interesting problem, I wrote this function to solve it in a nice an non-exceptional way :)

var deepCheck = function(arr, indexes) {
    var level = arr;
    while(indexes.length) {
         var v = indexes.shift()

         if(!level[v]) {
             return false;
         }

         level = level[v];
    }  

    return true;
};

Now say you have this:

arr[foo][bar][baz];

You would check it using...

deepCheck(arr, [foo, bar, baz]);

Maybe I should point out that I do kind of agree that if you indeed have very very long arrays like that, it does sound like a design issue.

Upvotes: 1

Blindy
Blindy

Reputation: 67447

Put the code accessing it between try and catch. If it works, it works, if not you get a nice exception and you can react accordingly.

As a side note, I shudder to think of what prompted you to design your system like that...

Upvotes: 0

Joe
Joe

Reputation: 82634

I can't think of anything better than:

var defined = false;
try {
   defined = !!arr[5][1][6][2][5][3][7]
} catch(e)
{
   // nothing
}

But seriously bad design.

Upvotes: 2

Related Questions