3

I am creating a very lightweight search functionality that takes the following:

if (searchStr == people.first_name ||
    searchStr == people.last_name || 
    searchStr == people.job || 
    searchStr == people.skills.forEach(function(x) { return x })) {
  Results.push(people)
}

searchStr is the search string; 'people' is a person object that has a single first and last name and a job, but only one of those thats an array is people.skills -- is there anyway I can traverse through that array in the if-conditional with an anonymous function?

Alberto Zaccagni
  • 29,658
  • 11
  • 72
  • 103
rahul2001
  • 1,367
  • 1
  • 16
  • 30

6 Answers6

6

You can use Array.prototype.some to evaluate whether a condition is true on at least one entry in an array. This is better than Array.prototype.filter because it will exit early on the first entry to evaluate as true.

if (searchStr == people.first_name ||
    searchStr == people.last_name || 
    searchStr == people.job || 
    people.skills.some(function(x) { return searchStr == x })) {
  Results.push(people)
}

Array.prototype.some is new in Ecmascript 5 which is fairly well supported now.


You could potentially improve on your search by doing a partial term search instead of an exact search by switching your equality comparisons with Array.prototype.indexOf to see if the string contains the search term.

if (contains(people.first_name, searchStr) ||
    contains(people.last_name, searchStr) || 
    contains(people.job, searchStr) || 
    people.skills.some(function(x) { return contains(x, searchStr); })) {
  Results.push(people)
}

function contains(a, b) {
  return a.indexOf(b) >= 0;
}
Daniel Imms
  • 45,529
  • 17
  • 143
  • 160
  • This worked! And to clarify, 'return searchStr == x' is returning true if there is a match and if there is a match, that person is pushed into Results[], correct? – rahul2001 Apr 30 '15 at 16:35
  • Indeed, it does. However, consider using `indexOf` as per my answer, as it's less verbose. The `some` method is usually used to perform more complex queries. – Witiko Apr 30 '15 at 16:38
3

The Array.prototype.some method serves this purpose:

if (searchStr == people.first_name ||
    searchStr == people.last_name || 
    searchStr == people.job || 
    people.skills.some(function(skill) {
      return searchStr == skill;
    })) {
  Results.push(people)
}

But using an anonymous function is unnecessary in this case. We can use the Array.prototype.indexOf method:

if (searchStr == people.first_name ||
    searchStr == people.last_name || 
    searchStr == people.job || 
    people.skills.indexOf(searchStr) != -1) {
  Results.push(people)
}

or, more idiomatically:

    people.skills.indexOf(searchStr)+1

Be aware that the Array.prototype.every, some, forEach, filter, reduce and reduceRight methods are a part of ECMAScript 5 and are therefore not supported in older browsers supporting only ECMAScript <=3.1. You should use a polyfill, if this is an issue.

Witiko
  • 2,857
  • 3
  • 24
  • 40
2

You can use indexOf to determine if a value exists in the array using javascript, if you really have to traverse the array, then use the some function like @DanielImms recommend.

if (searchStr == people.first_name ||
    searchStr == people.last_name || 
    searchStr == people.job || 
    people.skills.indexOf(searchStr)>-1) {
  Results.push(people)
}
Community
  • 1
  • 1
Tom Sarduy
  • 16,878
  • 8
  • 67
  • 83
  • The `-1` should probably be `+1`. Your statement returns `false` only when the `searchStr` is the first member of the `people.skills` array. – Witiko Apr 30 '15 at 16:42
  • @Witiko: My mistake, I forgot the `>` symbol :) And you mean the `+1` should be `-1` right? – Tom Sarduy Apr 30 '15 at 16:44
1

Another option is using Array.reduce(), which returns a single value.

Try this:

if (searchStr == people.first_name ||
    searchStr == people.last_name || 
    searchStr == people.job || 
    people.skills.reduce(function(p,c) {
       return p || (searchStr == c);
      },false)
}
S McCrohan
  • 6,457
  • 1
  • 28
  • 37
1
var searchSkills = [].concat.apply([], people.skills);

if (searchStr == people.first_name ||
    searchStr == people.last_name || 
    searchStr == people.job || 
    searchSkills.indexOf(searchStr) >= 0 {
  Results.push(people)
}

I'll leave this up for posterity's sake, but this method probably would only be useful if people.skills is multi-dimensional.

As a side-note, I'd suspect indexOf is much more performant than a filter map or some execution.

Josh Burgess
  • 9,058
  • 31
  • 45
1

And for the sake of thoroughness, if you were on the cutting edge and using Ecmascript 7, you could use Array.prototype.includes()

if (searchStr == people.first_name ||
    searchStr == people.last_name || 
    searchStr == people.job || 
    people.skills.includes(searchStr)
)
S McCrohan
  • 6,457
  • 1
  • 28
  • 37