8

I have an array of 109582 strings ordered alphabetically. My web application will be making a lot of rapid checks for whether a given string is contained in the array. Obviously I could make a wrapper class that is a hash table or binary tree, but is there any native JavaScript data structure that I can use instead?

user3609145
  • 93
  • 1
  • 3

2 Answers2

13

Sure. Make an dictionary object

dict = {
  string1: 1,
  string2: 1,
etc

It's guaranteed to provide O(1) lookup time.

gog
  • 10,367
  • 2
  • 24
  • 38
  • This is definitely the fastest. if (dict[string]) – Zack Argyle May 06 '14 at 16:59
  • 2
    Big O notation isn't the only concern. Wall-time measurements matter to. I'd suggest that the OP time to test if using one hash/object is better, or if he should at least create a hash for each first letter. – Jeremy J Starcher May 06 '14 at 17:00
  • 1
    Nothing does actually guarantee `O(1)` lookup time. True, most implementations do use hash maps for objects, but they could choose anything else as well. – Bergi May 06 '14 at 17:26
  • Is this would be faster than using an Array? – TripleS Sep 02 '16 at 14:42
7

There are various suitable structures and approaches, see below how they perform.

Array
  • for loop
  • for loop (reversed)
  • array.includes(target)
Set
  • set.has(target)
Object
  • obj.hasOwnProperty(target)
  • target in obj <- 1.29% slower
  • obj[target] <- fastest
Map
  • map.has(target) <- 2.94% slower
Results from January 2021, Chrome 87

enter image description here

JSBench tests https://jsbench.me/3pkjlwzhbr/1

// https://jsbench.me/3pkjlwzhbr/1
// https://docs.google.com/spreadsheets/d/1WucECh5uHlKGCCGYvEKn6ORrQ_9RS6BubO208nXkozk/edit?usp=sharing
// JSBench forked from https://jsbench.me/irkhdxnoqa/2

var theArr = Array.from({ length: 10000 }, (_, el) => el)
var theSet = new Set(theArr)
var theObject = Object.assign({}, ...theArr.map(num => ({ [num]: true })))
var theMap = new Map(theArr.map(num => [num, true]))

var theTarget = 9000


// Array

function isTargetThereFor(arr, target) {
  const len = arr.length
  for (let i = 0; i < len; i++) {
    if (arr[i] === target) {
      return true
    }
  }
  return false
}
function isTargetThereForReverse(arr, target) {
  const len = arr.length
  for (let i = len; i > 0; i--) {
    if (arr[i] === target) {
      return true
    }
  }
  return false
}

function isTargetThereIncludes(arr, target) {
  return arr.includes(target)
}

// Set

function isTargetThereSet(numberSet, target) {
  return numberSet.has(target)
}

// Object 

function isTargetThereHasOwnProperty(obj, target) {
  return obj.hasOwnProperty(target)
}
function isTargetThereIn(obj, target) {
  return target in obj
}
function isTargetThereSelectKey(obj, target) {
  return obj[target]
}

// Map

function isTargetThereMap(numberMap, target) {
  return numberMap.has(target)
}

This answer is migrated from https://stackoverflow.com/a/65604244/985454

Qwerty
  • 29,062
  • 22
  • 108
  • 136
  • 2
    It's worth noting that while `map` is indeed slower, you can map `:`, while Object only allows `:` _(I know the question is specific to string, but since your answer is so thorough I couldn't help but highlight the reason behind map' performance tradeoff )_ – Nebu Feb 26 '22 at 22:00