1

I understand I can search for an ( a single item in an array) several different ways. Iterate with for loops, foreach, recursive structures etc, but I am not trying to do that as I am searching for multiple items at a time.

For instance I may have an array of objects with this model:

people: [{name: "howdy", date: 2/2, sex: male}, {name: "jack", date: 3/3, sex: male}]

I want to know if howdy and jack are there at the same time. or maybe I want to know if howdy and jack are both in the array of people. Or maybe I want to know if howdy and Jack are both there by searching through the people array for matches based on birthday and sex.

I know how to do it one at a time but not searching by multiple values. I found this on stackover flow but I don't understand it. Is there a simpler way to search an array to find matches in the array based on multiple keys?

This did not work:

function containsAll(needles, haystack){

    for(var i = 0, len = needles.length; i <len; i++){
        if($.inArray(needles[i], haystack) == -1_ return false
    }
        return true;

}


containsAll([34, 78, 89], [78, 67, 34, 99, 56, 89]); // true

containsAll([34, 78, 89], [78, 67, 99, 56, 89]); // false

containsAll([34, 78, 89], [78, 89]); // false
messerbill
  • 5,499
  • 1
  • 27
  • 38
  • Possible duplicate of [Check if every element in one array is in a second array](https://stackoverflow.com/questions/8628059/check-if-every-element-in-one-array-is-in-a-second-array) – Nope Mar 06 '18 at 16:25
  • `this did not work:` it does if you get rid of the syntax error -> `== -1_` -> `== -1)` – Keith Mar 06 '18 at 16:25
  • I do but what element is this attached to? ($.inArray(needles[i]) is the class inArray? – baryjones23saturn Mar 06 '18 at 16:25
  • `$.inArray` it's a jquery utility method.. – Keith Mar 06 '18 at 16:26
  • I see so $needle[i] is the class it is selecting but we are running a method called inArray first. Am I understanding this correctly? – baryjones23saturn Mar 06 '18 at 16:29
  • Note that when comparing objects instead of just numbers you can't just do `if($.inArray(needles[i], haystack)` as you will need to match all properties of the objects with each other. You might not get the answer you actually need using numbers in your example arrays but wanting to compare objects.... – Nope Mar 06 '18 at 16:43
  • I actually wanted to compare objects? for instance I will take the value from a post form and create a search with that. city, name, state. I need to search through objects like [{city: chicago, zip: 545454, state: "il"}, ...{}] I'm creating a filter that has dropdown inputs for stores locations a user can select city or state or all 3 and it will search through an array with differnt stores and find a match. later I may add more items to filter search through. If I can get it to work with 2 I can make it work with more. I thought we had it and then I learned it won't work with objects – baryjones23saturn Mar 06 '18 at 18:10

2 Answers2

2

Your approach:

Move the return true out from the for-loop

function containsAll(needles, haystack) {

  for (var i = 0, len = needles.length; i < len; i++) {
    if ($.inArray(needles[i], haystack) === -1) {
      return false
    }
  }
  
  return true;
}


console.log(containsAll([34, 78, 89], [78, 67, 34, 99, 56, 89])); // true
console.log(containsAll([34, 78, 89], [78, 67, 99, 56, 89])); // false
console.log(containsAll([34, 78, 89], [78, 89])); // false
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

You can use the functions every and includes:

function containsAll(needles, haystack) {
  return needles.every(function(p) {
    return haystack.includes(p);
  });
}

console.log(containsAll([34, 78, 89], [78, 67, 34, 99, 56, 89])); // true
console.log(containsAll([34, 78, 89], [78, 67, 99, 56, 89])); // false
console.log(containsAll([34, 78, 89], [78, 89]));

Full ES6:

var containsAll = (needles, haystack) => needles.every(p => haystack.includes(p));
  
console.log(containsAll([34, 78, 89], [78, 67, 34, 99, 56, 89])); // true
console.log(containsAll([34, 78, 89], [78, 67, 99, 56, 89])); // false
console.log(containsAll([34, 78, 89], [78, 89]));

To check the both names are within an array like this:

[{name: "howdy", date: 2/2, sex: male}, {name: "jack", date: 3/3, sex: male}]

Follow this approach:

var containsAll = (needles, haystack) => needles.every(p => haystack.findIndex(h => h.name === p) > -1);

console.log(containsAll(['howdy', 'jack'], [{name: "howdy", date: '2/2', g: 'm'}, {name: "jack", date: '3/3', g: 'm'}]));
console.log(containsAll(['howdy', 'ele'], [{name: "howdy", date: '2/2', g: 'm'}, {name: "jack", date: '3/3', g: 'm'}]));

Following your real scenario:

The condition will be h.animal === p.animal

var containsAll = (needles, haystack) => needles.every(p => haystack.findIndex(h => h.animal === p.animal) > -1);

console.log(containsAll([{
  num: 34,
  animal: "chicken",
  city: "chicago"
}], [{
  number: 78,
  name: "chicken",
  num: 34
}, 99, 56, "hello", {
  num: 34,
  animal: "chicken",
  city: "chicago"
}]));
Ele
  • 33,468
  • 7
  • 37
  • 75
  • Why declare `var array = [{name: "howdy", date: '2/2', 'g': 'm'}, {name: "jack", 'date': '3/3', 'g': 'm'}]` and not use it? I assume if objects are compared all sub properties need to be manually compared to establish a match? – Nope Mar 06 '18 at 16:39
  • @Nope it was a big typo xD – Ele Mar 06 '18 at 16:40
  • @Nope if they are object, definitely we need to compare sub properties. – Ele Mar 06 '18 at 16:41
  • I am trying to compare objects: – baryjones23saturn Mar 06 '18 at 18:56
  • console.log(containsAll([{num: 34, animal: "chicken", city: "chicago"}], [{number: 78, name: "chicken", num: 34}, 99, 56, "hello", {num: 34, animal: "chicken", city: "chicago"}])); // true – baryjones23saturn Mar 06 '18 at 18:56
  • I marked it as correct I think, please double check. One question though and this is more of a general question regarding the filter I am creating. If I have a filter of 4 inputs for instance, do I need to have a if statement for every single choice for my filter to work? ie they select 1,3,4 and leave option 2 unchecked. a if statement for that. They leave 1 open and mark 2 and 3 and leave 4 open and if statement for that etc. I'm at like 16 if statements to cover all the cases. I am certain i am doing this wrong. Is there a better way? – baryjones23saturn Mar 06 '18 at 20:32
  • @baryjones23saturn If you have different situations for checked options, you will need to add several conditions `if-else` Etc. – Ele Mar 06 '18 at 20:53
  • @baryjones23saturn btw, the answer it wasn't accepted :-) – Ele Mar 06 '18 at 20:54
  • so applications that have say 20 fields have 2**20 or however many combinations there are of possible choices? How do people make search filters than that have several inputs? – baryjones23saturn Mar 06 '18 at 20:55
  • who decides if the answer to my question is accepted? – baryjones23saturn Mar 06 '18 at 20:57
  • 1
    @baryjones23saturn that depends, if the entered values should be equals to some situation/values you can use logical operators: `input1 == somestring && input2 == somestring` so you don't need several `if` for these situations. – Ele Mar 06 '18 at 21:01
  • @baryjones23saturn there is a "check symbol" just below of the votes. – Ele Mar 06 '18 at 21:02
  • @baryjones23saturn `who decides if the answer to my question is accepted? ` - You Do by selecting the big checkmark on the answer. – Nope Mar 07 '18 at 10:15
0

If these arrays are primitives you can use includes:

function containsAll(needles, haystack){
    return needles.every(x => haystack.includes(x));
}

containsAll([34, 78, 89], [78, 67, 34, 99, 56, 89]); // true
containsAll([34, 78, 89], [78, 67, 99, 56, 89]); // false
containsAll([34, 78, 89], [78, 89]); // false

Updated:

If you don't know if arrays are primitives then you must check if it is primitive, if don't then check property by property:

function containsAll(needles, haystack){
  return needles.every(x => haystack.find(y => {
    if(typeof y == 'string' || typeof y == 'number') {
      return x == y;
    }
    return Object.keys(y).every(z => x[z] == y[z]);
  }));
}

console.log(containsAll([34, 78, 89], [78, 67, 34, 99, 56, 89]));
//true

console.log(containsAll([34, 78, 89], [78, 67, 99, 56, 89])); 
// false

console.log(containsAll([34, 78, 89], [78, 89])); 
// false

console.log(containsAll([{num: 34, animal: "chicken", city: "chicago"}], [{number: 78, name: "chicken", num: 34}, 99, 56, "hello", {num: 34, animal: "chicken", city: "chicago"}]));
// true

console.log(containsAll([{num: 35, animal: "chicken", city: "chicago"}], [{number: 78, name: "chicken", num: 34}, 99, 56, "hello", {num: 34, animal: "chicken", city: "chicago"}]));
// false
guijob
  • 4,413
  • 3
  • 20
  • 39
  • console.log(containsAll([{num: 34, animal: "chicken", city: "chicago"}], [{number: 78, name: "chicken", num: 34}, 99, 56, "hello", {num: 34, animal: "chicken", city: "chicago"}])); // true – baryjones23saturn Mar 06 '18 at 18:58
  • @baryjones23saturn i've added an approach when you can have primitives and non-primitives arrays – guijob Mar 06 '18 at 19:26
  • If my search filter had for input fields for instance, would I have to have several different if statements to cover all cases. for instance if I had 4 fields of name, dob, height, weight. would I need a filter for if they selected all 4 inputs, if they selected 3 inputs, if they selected 2 inputs etc. Then if they selected name and dob and left the other 2 input fields blank etc. Surely there is an easier way to do this vs a bunch of if statements. If I had 20 fields it would take forever. – baryjones23saturn Mar 06 '18 at 20:52