I created this function that allows you to declare a string, then multiple instances of a substring. This uses a hash map to keep track of strings that have already been searched for and upon each call of its returning function will give you the next instance of that substring.

I'm wondering if there's a way to do this without crypto. I have the option of applying the strings as a object property but I didn't want to overload memory with those.

I'm not sure if there's a native JavaScript way to do this, either, so I'm open to suggestions of native code or other libraries that achieve this.

var crypto = require('crypto')
var S = require('underscore.string')
var _ = require('lodash')

/** returns a md5 hash of the content */
function getHash (content) {
  var shasum = crypto.createHash('md5')
  return shasum.update(content).digest('hex')

function multiIndexOf (s) {
  var map = []
  return function (ss) {
    var hash = getHash(ss)
    var indexes = indexesOf(s, ss)
    var countMap = _.countBy(map)
    var instance = countMap[hash] || 0
    return indexes[instance]

function indexesOf (s, ss) {
  var instances = S.count(s, ss)
  return _.chain(instances)
  .reduce(function (indexes, instance) {
    var lastIndex = _.last(indexes)
    var start = (typeof lastIndex === 'undefined') ? 0 : lastIndex + ss.length
    var index = s.indexOf(ss, start)
    return indexes
  }, [])

var find = multiIndexOf('hello world, hello darling')

console.log(find('hello')) // => 0
console.log(find('hello')) // => 13

1 Answer 1


I don't believe hashing the key provides any functionality: storing the searched string directly into the map would work.

Your map variable is effectively working as a list of hashed keys, not as an actual key-value mapping. Instead of pushing the keys to the collection, override the existing key if it exists, and set the value to be the last found index.

Utilizing the map this way, your code simplifies immensely, and it no longer relies on third-party libraries:

function multiIndexOf (s) {
  var map = [];
  return function (key) {
    var nextIndex = map[key] + 1;
    map[key] = s.indexOf(key, nextIndex);
    return map[key];

var find = multiIndexOf('hello world, hello darling')

// Example usage
console.log(find('hello')) // => 0
console.log(find('hello')) // => 13
console.log(find('hello')) // => -1
console.log(find('hello')) // => 0
console.log(find('hello')) // => 13
console.log(find('el')) // => 1
console.log(find('ell')) // => 1
console.log(find('ell')) // => 14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.