0

UPDATED (formulated the problem wrong, see note below)

I have an object that has a set of properties that are named with numbers as shown in the example. The 'numbered names' are not necessarily consecutive, nor do I know where they start or end. I do know that other properties will not be named with numbers.
I know that myObject["propName"] is the same as myObject.propName, but I deliberately write it in the first way because myObject.0 looks weird and doesn't get recognized by all editors.

How do I get the min- and maximum array index?

So in a situation like this

myObject["0"] = undefined
myObject["1"] = {}
myObject["2"] = undefined
myObject["3"] = {}
myObject["4"] = {}
myObject["5"] = undefined
myObject["someOtherProperty"] = {}

would give me this

minIndex(myObject) == 1
maxIndex(myObject) == 4

To all the answers before this edit
Thanks for your replies. I shouldn't have posted this question in a hurry and should have re-read it before committing. It was late and I was in a hurry. My apologies.
By actually seeing my wrong statement (using an array instead of an object) I think that, based on answers for my reformulated problem, I might need to rewrite my code to use an array instead of an object. The reason I'm using an object rather then an array is material for another question.

Efforts so far
I have tried finding a way of converting the property names to an array and then looping through them, but that has proven cludgy. I'm kind of looking for a less error-prone and elegant way.

Boris Callens
  • 90,659
  • 85
  • 207
  • 305
  • 2
    By the way... you can remove items from an array without the ugly holes with array.splice(). Maybe this eradicates the question in the first place. – Kai Mattern Aug 09 '12 at 20:18
  • 4
    I would close the question. These types of questions, besides not showing any research effort, always end up in a Crazy Coding Contest (C3). There is not enough time on Earth to correct everything in all the answers, and if I downvote most of them for various reasons, angry townspeople might attack my home. – kapa Aug 09 '12 at 20:29
  • 1
    Wow, haven't looked this for a workday and then this. Quite shocked. Yes, I'm quite new to real javascript. Furthermore I think that, in my effort to give only the core problem, I might have boiled the question down incorrect and posed the problem wrong. I'm going to try and review the entire thing. But really: ouch – Boris Callens Aug 10 '12 at 15:56
  • @Esailija, you are right to question this. Reformulated question, added response to you request in OP – Boris Callens Aug 10 '12 at 16:11
  • @BorisCallens ah it's not an array at all, interesting. – Esailija Aug 10 '12 at 16:33
  • 1
    @Boris Callens I updated my answer. Let me know if this works given the "updated scenario" :) – Nick Aug 10 '12 at 19:31

7 Answers7

10

Edit: Aha! Now the problem becomes more interesting.

Solution 1: Let's solve this in one shot, shall we? For max:

function maxIndex(obj){
    var max = -1;
    for(var i in myObject){
        var val = parseInt(i);
        if(isFinite(val)){
            if(typeof obj[val] !== 'undefined' && val > max){
                max = val;
            }
        }
    }
    return max;
}

I think you can convert this to min on your own ;)

Solution 2: Here I'll your object back into what we originally thought it was, in case you really loved one of the other solutions. Then the rest of the answer applies.

function convertObject(obj){
    var output = [];
    for(var i in myObject){
        var val = parseInt(i);
        if(isFinite(val)){         
            output[val] = obj[i]; //Gotta love JS
        }
    }
    return output;
}

Continue as planned!


To find the smallest, begin at the bottom and work your way up until you find it.

function minIndex(myArray){
    for(var i = 0; i < myArray.length; i++){
        if(typeof myArray[i] !== 'undefined')
            return i;
    }
}

To get the biggest, start at the top.

function maxIndex(myArray){
    for(var i = myArray.length - 1; i >= 0; i--){
        if(typeof myArray[i] !== 'undefined')
            return i;
    }
}

Both are worst case O(n). You can't really do better because the whole array could be empty, and you'd have to check every element to be positive.

Edit: As is mentioned, you can also check if something is not undefined by simply writing if(myArray[i]). Whatever suits your fancy.

Nick
  • 8,964
  • 4
  • 26
  • 37
  • 3
    `null == undefined`... I don't get why not people simply use `typeof x == 'undefined'`, which is a proven way for testing for `undefined`. – kapa Aug 09 '12 at 20:17
  • 1
    if we're going to use != might as well use if(myArray[i]) and second if you're worried about performance just use a single loop and return {min:1, max:4} – Liviu T. Aug 09 '12 at 20:19
  • @bažmegakapa Simply rushed it is all. I've been jumping between a lot of languages today ^.^ – Nick Aug 09 '12 at 20:21
  • @LiviuT. Re: O(1) solution, nice try, but if you read the question carefully it mentions that the slots are randomly filled or not. – Nick Aug 09 '12 at 20:23
  • 1
    @ngmiceli One more thing: `!` has a higher precedence than `===`. I suggest using `!==` instead. – kapa Aug 09 '12 at 20:23
  • 1
    And concerning your edit: `if (myArray[i])` is a very bad idea. It gives false for `undefined` - and for all the falsy values also. – kapa Aug 09 '12 at 20:26
  • @ngmiceli i din't mention O(1) :). I meant if you don't want 2xO(n) you could merge the functions in one – Liviu T. Aug 09 '12 at 20:27
  • @LiviuT. Ah! My apologies, I thought you were suggesting returning a constant value, answering the *exact* problem he mentioned above. Yes, you are completely correct, but its technically not what the OP asked for :) – Nick Aug 09 '12 at 20:28
  • Beware of != since it does type coersion. JSLint doesn't allow it, for good reason. I disagree with JSLint's nazi enforcement of spacing and style that I don't like, but it's a great tool otherwise. – Almo Aug 09 '12 at 20:29
  • `!= null` is legit and robust. It's not the same as checking for falsy values, it's the same as `!== null && !== undefined` which is exactly what you want in a broken language with 2 types of undefined values. Use `in` or `.hasOwnProperty` to check for existence as `undefined` can be a value of a key. Otherwise, `!= null/undefined` does the job. – Esailija Aug 09 '12 at 20:32
  • Thanks for the reviewed solution. This was kind of what I tried by myself ('xcept mine wasn't compiling ;). @Esailija's solution is more the succint, clean and tidy syntax I was aiming for though. Thank both for your patience with my question :) – Boris Callens Aug 11 '12 at 10:38
1

Try looping through the array until you find the 1st non-undefined element.

function minIndex(arr){
    for(var i = 0, len = arr.length; i < len; i++){
        if(arr[i] !== undefined){
            return i;
        }
    }
}

For max index, do the same thing, except in reverse.

function maxIndex(arr){
    for(var i = arr.length-1, len = 0; i >= len; i--){
        if(arr[i] !== undefined){
            return i;
        }
    }
}
gen_Eric
  • 223,194
  • 41
  • 299
  • 337
1
var myObject = {};
myObject["0"] = undefined;
myObject["1"] = {};
myObject["2"] = undefined;
myObject["3"] = {};
myObject["4"] = {};
myObject["5"] = undefined;
myObject["someOtherProperty"] = {};

var keys = Object.keys(myObject).map(Number).filter(function(a){
    return isFinite(a) && myObject[a];
});

var min = Math.min.apply(Math, keys);
var max = Math.max.apply(Math, keys);

console.log(min, max); //Logs 1 and 4

Documentation and compatibility information for all:

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter

Esailija
  • 138,174
  • 23
  • 272
  • 326
  • This looks nice and tidy :) Had seen a post from John Resig about using apply for max. This incorporates it nicely. Had some concerns about compatibility, but the links seem to solve it. Nice and thanks :) – Boris Callens Aug 11 '12 at 10:35
0

Min:

for(var i = 0; i < myArray.length; i++) {
    if(myArray[i] != undefined) {
        return i;
    }
}

Max:

for(var i = myArray.length-1; i >= 0; i--) {
    if(myArray[i] != undefined) {
        return i;
    }
}
pizen
  • 464
  • 3
  • 4
0

try something like this:

function minIndex(var array){
   for(var i = 0; i < array.length; i++)
   {
      if(typeof array[i] != "undefined")
      return i;
   }
   return null;
}

function maxIndex(var array){
   var returnIndex = -1;
   for(var i = 0; i < array.length; i++)
   {
      if(typeof array[i] != "undefined")
      returnIndex = i;
   }
   if(returnIndex !== -1) return returnIndex;
   else return null;
}
Phillip Schmidt
  • 8,805
  • 3
  • 43
  • 67
-1
var max=0;
var min=myArray.length;
for (var i in myArray)
    if (myArray[i]!==undefined)
    {
        max=Math.max(i, max);
        min=Math.min(i, min);
    }
Wolfgang Stengel
  • 2,867
  • 1
  • 17
  • 22
  • 1
    Don't use `for...in` for arrays. Plus since the values are explicitly set to `undefined` all the keys will appear here. – gen_Eric Aug 09 '12 at 20:17
  • You'd have to test for the values of course, but the for...in method has the advantage of checking only defined values, not all possible values starting from 0. – Wolfgang Stengel Aug 09 '12 at 20:18
  • Problem is, in the example, all the values *are* defined. Also: http://stackoverflow.com/questions/500504/javascript-for-in-with-arrays – gen_Eric Aug 09 '12 at 20:20
  • Edited to illustrate what I mean. – Wolfgang Stengel Aug 09 '12 at 20:22
  • Don't understand the downvotes... I was trying to avoid having to run through 1000 elements if we have an array like this: var a=[]; a[1000]=5;. – Wolfgang Stengel Aug 09 '12 at 20:45
  • I think the downvotes are because it's frowned upon to use `for...in` on arrays. – gen_Eric Aug 09 '12 at 20:46
  • Yes, but why is it frowned upon in this specific case? – Wolfgang Stengel Aug 09 '12 at 20:47
  • I've just always learned never to use `for...in` on arrays. P.S. I didn't downvote. – gen_Eric Aug 09 '12 at 20:48
  • @WolfgangStengel Rocket already posted an interesting link about why not to use it for arrays. `myArray.x = 1` would simply cause your code to result in `x` for the max - even though that is not part of the array itself. This leads to hours of debugging in certain cases - which can simply be avoided by sticking to best practices. The check for `undefined` can also be improved, but I would not downvote for that. – kapa Aug 09 '12 at 21:46
-1

this takes advantage of the fact that for..in only iterates over defined elements, and uses the index:

function minIndex(arr){ for(el in arr){return el} }

function maxIndex(arr){var v; for(el in arr){v = el}; return v }

CAVEATS: The second function is not very efficient though, since it loops through the entire array. This wont work if you are EXPLICITLY setting the undefined indexes.

Matt Van Horn
  • 1,654
  • 1
  • 11
  • 21
  • In the example. the values are literally defined as `undefined`, so this won't work. Plus you shouldn't use `for...in` for Arrays. – gen_Eric Aug 09 '12 at 20:32
  • Just realized about the explicit definitions. I tried it by just adding the defined values. I'm lazy (which is a cardinal virtue of programmers) Edited. – Matt Van Horn Aug 09 '12 at 20:36