JVG
JVG

Reputation: 21150

Javascript checking whether string is in either of two arrays

I'm pulling my hair out over this one. I have two arrays, likes & dislikes, both filled with about 50 strings each.

I also have a JSON object, data.results, which contains about 50 objects, each with an _id parameter.

I'm trying to check find all the objects within data.results that aren't in both likes and dislikes.

Here's my code at present:

var newResults = []
      for(var i = 0; i<data.results.length; i++){
        for(var x = 0; x<likes.length; x++){
          if(!(data.results[i]._id == likes[x])){
            for(var y = 0; y<dislikes.length; y++){
                if(!(data.results[i]._id == dislikes[y])){
                  newResults.push(data.results[i]);
                  console.log("pushed " + data.results[i]._id);
                }
                else
                {
                   console.log("They already HATE " + data.results[i]._id + " foo!"); //temp
                }
            }
          }
          else
          {
             console.log(data.results[i]._id + " is already liked!"); //temp
          }
        }
      }

As you can see, I'm iterating through all the data.results objects. Then I check whether their _id is in likes. If it isn't, I check whether it's in dislikes. Then if it still isn't, I push it to newResults.

As you might expect by looking at it, this code currently pushes the result into my array once for each iteration, so i end up with a massive array of like 600 objects.

What's the good, simple way to achieve this?

Upvotes: 1

Views: 89

Answers (4)

Moritz Roessler
Moritz Roessler

Reputation: 8611

When checking whether an Array contains an element, Array.prototype.indexOf (which is ECMAScript 5, but shimmable for older browsers), comes in handy. Even more when combined with the bitwise NOT operator ~ and a cast to a Boolean !

Lets take a look how this could work.

Array.prototype.indexOf returns -1 if an Element is not found.

Applying a ~ to -1 gives us 0, applying an ! to a 0 gives us true.

So !~[...].indexOf (var) gives us a Boolean represantation, of whether an Element is NOT in an Array. The other way round !!~[...].indexOf (var) would yield true if an Element was found.

Let's wrap this logic in a contains function, to simply reuse it.

function contains (array,element) {
    return !!~array.indexOf (element);
}

Now we only need an logical AND && to combine the output, of your 2 arrays, passed to the contains function.

var likes = ["a","b","f"] //your likes
var dislikes = ["c","g","h"] //your dislikes

var result = ["a","c","d","e","f"]; //the result containing the strings
var newresult = []; //the new result you want the strings which are NOT in likes or dislikes, being pushed to

for (var i = 0,j;j=result[i++];) //iterate over the results array
     if (!contains(likes,j) && !contains (dislikes,j)) //check if it is NOT in likes AND NOT in dislikes
           newresult.push (j) //if so, push it to the newresult array.

console.log (newresult) // ["d","e"]

Here is a Fiddle

Edit notes:
1. Added an contains function, as @Scott suggested

Upvotes: 1

user2587132
user2587132

Reputation:

Try first creating an array of common strings between likes and dislikes

var commonStrAry=[];
for(var i = 0; i<likes.length; i++){
for(var j=0; j<dislikes.length; j++){
    if(likes[i] === dislikes[j]){
        commonStrAry.push(likes[i] );
    }
}
}

then you can use this to check against data.results and just remove the elements that don't match.

Upvotes: 0

Moos Hueting
Moos Hueting

Reputation: 670

for (var i = 0; i < data.results.length; i++) {
    isInLiked = (likes.indexOf(data.results[i]) > -1);
    isInHated = (dislikes.indexOf(data.results[i]) > -1);
    if (!isInLiked && !isInHated) {
        etc...
    }
}

Upvotes: 3

Valentin D
Valentin D

Reputation: 725

Use likes.indexOf(data.results[i]._id) and dislikes.indexOf(data.results[i]._id).

if (likes.indexOf(data.results[i]._id) != -1)
{
// they like it :D
}

Upvotes: 0

Related Questions