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
  • 30,779
  • 11
  • 72
  • 106
rahul2001
  • 1,577
  • 2
  • 17
  • 32

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
  • 47,944
  • 19
  • 150
  • 166
  • 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
  • 3,167
  • 3
  • 25
  • 43
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
Tomas Ramirez Sarduy
  • 17,294
  • 8
  • 69
  • 85
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,663
  • 1
  • 30
  • 39
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,327
  • 33
  • 46
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,663
  • 1
  • 30
  • 39