Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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
    map.push(hash)
    return indexes[instance]
  }
}

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

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

console.log(find('hello')) // => 0
console.log(find('hello')) // => 13
share|improve this question
up vote 3 down vote accepted

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
share|improve this answer
    
This is really great! Thanks! – ThomasReggi Aug 20 '15 at 3:31

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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