17

I have a group of strings in Javascript and I need to write a function that detects if another specific string belongs to this group or not.

What is the fastest way to achieve this? Is it alright to put the group of values into an array, and then write a function that searches through the array?

I think if I keep the values sorted and do a binary search, it should work fast enough. Or is there some other smart way of doing this, which can work faster?

Alexis Tyler
  • 1,394
  • 6
  • 30
  • 48
Gabriel
  • 2,313
  • 9
  • 29
  • 41

9 Answers9

25

Use a hash table, and do this:

// Initialise the set

mySet = {};

// Add to the set

mySet["some string value"] = true;

...

// Test if a value is in the set:

if (testValue in mySet) {
     alert(testValue + " is in the set");
} else {
     alert(testValue + " is not in the set");
}
Simon Howard
  • 8,999
  • 5
  • 28
  • 21
  • 2
    Using the "in" operator is probably the more elegant way of doing it. +1 – Tomalak Nov 21 '08 at 10:30
  • 1
    While trying to dance around AngularJS' ng-if, I came up with this syntax (right after reading this answer): `({value1: 1, value2: 1})[ 'value2' ]` - a self-contained map test. – Kevin Teljeur Jul 19 '17 at 15:57
8

You can use an object like so:

// prepare a mock-up object
setOfValues = {};
for (var i = 0; i < 100; i++)
  setOfValues["example value " + i] = true;

// check for existence
if (setOfValues["example value 99"]);   // true
if (setOfValues["example value 101"]);  // undefined, essentially: false

This takes advantage of the fact that objects are implemented as associative arrays. How fast that is depends on your data and the JavaScript engine implementation, but you can do some performance testing easily to compare against other variants of doing it.

If a value can occur more than once in your set and the "how often" is important to you, you can also use an incrementing number in place of the boolean I used for my example.

Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • This doesn't work. setOfValues[x] where x is not in the set will not evaluate to undefined, it will produce an error. What you want is: "x in setOfValues" to test for membership. – Simon Howard Nov 21 '08 at 09:31
  • It will evaluate to undefined. It will not result in an error. Try it out. – Tomalak Nov 21 '08 at 10:01
7

Stumbled across this and realized the answers are out of date. In this day and age, you should not be implementing sets using hashtables except in corner cases. You should use sets.

For example:

> let set = new Set();
> set.add('red')

> set.has('red')
true
> set.delete('red')
true
> set.has('red')
false

Refer to this SO post for more examples and discussion: Ways to create a Set in JavaScript?

melchoir55
  • 6,842
  • 7
  • 60
  • 106
6

A comment to the above mentioned hash solutions. Actually the {} creates an object (also mentioned above) which can lead to some side-effects. One of them is that your "hash" is already pre-populated with the default object methods.

So "toString" in setOfValues will be true (at least in Firefox). You can prepend another character e.g. "." to your strings to work around this problem or use the Hash object provided by the "prototype" library.

Ralf
  • 427
  • 3
  • 4
2

A possible way, particularly efficient if the set is immutable, but is still usable with a variable set:

var haystack = "monday tuesday wednesday thursday friday saturday sunday";
var needle = "Friday";
if (haystack.indexOf(needle.toLowerCase()) >= 0) alert("Found!");

Of course, you might need to change the separator depending on the strings you have to put there...

A more robust variant can include bounds to ensure neither "day wed" nor "day" can match positively:

var haystack = "!monday!tuesday!wednesday!thursday!friday!saturday!sunday!";
var needle = "Friday";
if (haystack.indexOf('!' + needle.toLowerCase() + '!') >= 0) alert("Found!");

Might be not needed if the input is sure (eg. out of database, etc.).

I used that in a Greasemonkey script, with the advantage of using the haystack directly out of GM's storage.

PhiLho
  • 40,535
  • 6
  • 96
  • 134
0

Using a hash table might be a quicker option.

Whatever option you go for its definitely worth testing out its performance against the alternatives you consider.

Chris Kimpton
  • 5,546
  • 6
  • 45
  • 72
0

Depends on how much values there are.

If there are a few values (less than 10 to 50), searching through the array may be ok. A hash table might be overkill.

If you have lots of values, a hash table is the best option. It requires less work than sorting the values and doing a binary search.

Burkhard
  • 14,596
  • 22
  • 87
  • 108
  • i thought everything in JS was a hash table, an arry is just 0=>firstentry, 1=>secondentry isnt it? – Andrew Bullock Nov 21 '08 at 09:40
  • @Trull: I doubt it. Array is different from Object, and probably optimized for performance, although it will depend on implementation. – PhiLho Nov 21 '08 at 11:51
0

I know it is an old post. But to detect if a value is in a set of values we can manipulate through array indexOf() which searches and detects the present of the value

var myString="this is my large string set";
var myStr=myString.split(' ');
console.log('myStr contains "my" = '+ (myStr.indexOf('my')>=0));
console.log('myStr contains "your" = '+ (myStr.indexOf('your')>=0));

console.log('integer example : [1, 2, 5, 3] contains 5 = '+ ([1, 2, 5, 3].indexOf(5)>=0));
jafarbtech
  • 6,842
  • 1
  • 36
  • 55
0

You can use ES6 includes.

var string = "The quick brown fox jumps over the lazy dog.",
  substring = "lazy dog";

console.log(string.includes(substring));
Penny Liu
  • 15,447
  • 5
  • 79
  • 98