3

right now I'm doing something like this to match objects in an array:

for (var key in users)
{
if (users[key].userID==session)
{
 //do whatever
}
}

but I need to figure out how many times this matches, if it only matches once, then I want it to trigger the event (where it says "//do whatever")

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Dylan Cross
  • 5,918
  • 22
  • 77
  • 118

5 Answers5

4

You could use the array.filter method like this:

users.filter(function(a){return (a.userID==session)}).length == 1;

Although the user will need to be running a modern browser (js 1.6) or the filter method be polyfilled.

Sam Greenhalgh
  • 5,952
  • 21
  • 37
4

This quits looking as soon it finds 2 matches

var count= 0;
for(var key in users){
    if(users[key].userID== session)++count;
    if(count== 2) break;
}
if(count== 1){
    //do whatever
}
Alexis Tyler
  • 1,394
  • 6
  • 30
  • 48
kennebec
  • 102,654
  • 32
  • 106
  • 127
  • This answer is pure awesomeness, I upvoted it (and tried to downvote my own ans) the only reason I won't delete my ans is because it is interesting... I don't know how I always miss the easy solutions to easy problems – ajax333221 Feb 13 '12 at 03:45
2

Simply increment a variable and check if it's == 1 after the loop.

var matched = 0;
for (var key in users) {
    if (users[key].userID==session) {
        matched++;
    }
}

if (matched == 1) {
    // do something
}
ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
  • Ok thanks, this is how I was going to do it but I wasn't sure if there was a more efficient way of doing so. – Dylan Cross Feb 12 '12 at 22:09
  • 1
    From what I remember, the only way that might be a little faster than this is to generate an array with `Object.keys()`, then iterate with a `for` loop. But it was only marginally faster, and not supported in older browsers. Unless your object has like 100k members, efficiency should realistically not be a huge concern. – Kevin Ennis Feb 12 '12 at 22:24
  • Yeah that's true, I have just been rebuilding my site from the ground up to be far more efficient, so I always look for as efficient solutions, when possible. Because every part of the site that is just the slightest amount more efficient adds up – Dylan Cross Feb 12 '12 at 22:31
1

if you are worried because performance, you might want to check this out:

function isOnce(itm,arr){
    var first_match=-1;
    for(var i=0,len=arr.length;i<len;i++){
        if(arr[i]===itm){
            first_match=i;
            break;
        }
    }
    if(first_match!=-1){
        var last_match=-1;
        for(i=arr.length-1;i>first_match;i--){
            if(arr[i]===itm){
                last_match=i;
                break;
            }
        }
        if(last_match==-1){
            return true;
        }
    }
    return false;
}

You will notice savings when these two points met:

  • There are 2 or more matches
  • The first and last match are at least 1 space apart

In other words, you don't ever loop on the elements that are between first and last match. So the best case scenario would be:

arr=["a", ...(thousands of items here)... ,"a"];// you only looped 2 times!
ajax333221
  • 11,436
  • 16
  • 61
  • 95
  • Well I actually never thought about having it stop after it's already matched more than once, the rest would just be redundant, so wouldn't it be basically the same efficiency to add to the first answer "if(count<1){//continue}" – Dylan Cross Feb 12 '12 at 22:42
  • @DylanCross you can't make an `if` inside the loop, you need to wait for the loop to finish counting – ajax333221 Feb 12 '12 at 22:44
  • I don't see where the win is. If the array was ["a", "a", (thousands of items)] then your method is slower than doing one loop and breaking after finding the second match and quite a bit more complicated than it needs to be. – wheresrhys Feb 12 '12 at 23:14
  • @wheresrhys I updated my answer to remove the unnecessary loop. Now my code in the 'worstest' case scenario will make the same amount of loops than a normal one. – ajax333221 Feb 13 '12 at 00:38
0

I've got a feeling I missed something in your question, but if I understood it properly this should work, and is quite efficient as the loop stops as soon as a second match is found.

var firstMatch = null;

for (var key in users) {
  if (users[key].userID==session) {
    if (firstMatch) { // if a previous match was found unset it and break the loop
      firstMatch = null;
      break;
    } else { // else set it
      firstMatch = users[key];
    }
  }
}

if (firstMatch) {
    doSomethingTo(firstMatch); // maybe you don't need to pass in firstMatch, but it's available if you need to
}

Or the following loop does the same as the one above with a little less code

for (var key in users) {
  if (users[key].userID==session) {
    firstMatch = (firstMatch) ? null : users[key];
    if(!firstMatch) break;
  }
}
wheresrhys
  • 22,558
  • 19
  • 94
  • 162