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")

5 Answers 5

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
}
Sign up to request clarification or add additional context in comments.

1 Comment

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
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.

4 Comments

Well, do you know how much more efficient this method is over the previous one? I only ask because of the browser issue.
This creates a new array and calls a function for each element. While the overhead especially of calling the function is low, I highly doubt that it's more efficient than a plain loop.
Put together a test on jsperf.com
I doubt its any more efficient, I made the suggestion in the interests of brevity rather than performance.
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
}

3 Comments

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.
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.
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
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!

4 Comments

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}"
@DylanCross you can't make an if inside the loop, you need to wait for the loop to finish counting
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 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.
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;
  }
}

1 Comment

I've tried your second example, though I havent been able to get it to work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.