src/metrics/distance/sift4.js
function withoutTranspositions(maxOffset, maxDistance, a, b) {
  // Early termination
  if (a === b)
    return 0;

  const la = a.length,
        lb = b.length;

  if (!la || !lb)
    return Math.max(la, lb);

  let cursorA = 0,
      cursorB = 0,
      longestCommonSubsequence = 0,
      localCommonSubstring = 0;

  while (cursorA < la && cursorB < lb) {
    if (a[cursorA] === b[cursorB]) {
      localCommonSubstring++;
    }
    else {
      longestCommonSubsequence += localCommonSubstring;
      localCommonSubstring = 0;

      if (cursorA !== cursorB)
        cursorA = cursorB = Math.max(cursorA, cursorB);

      for (let i = 0; i < maxOffset && (cursorA + i < la || cursorB + i < lb); i++) {
        if (cursorA + i < la && a[cursorA + i] === b[cursorB]) {
          cursorA += i;
          localCommonSubstring++;
          break;
        }

        if (cursorB + i < lb && a[cursorA] === b[cursorB + i]) {
          cursorB += i;
          localCommonSubstring++;
          break;
        }
      }
    }

    cursorA++;
    cursorB++;

    if (maxDistance) {
      const tempDistance = Math.max(cursorA, cursorB) - longestCommonSubsequence;

      if (tempDistance === maxDistance)
        return maxDistance;

      if (tempDistance > maxDistance)
        return Infinity;
    }
  }

  longestCommonSubsequence += localCommonSubstring;

  return Math.max(la, lb) - longestCommonSubsequence;
}
function withoutTranspositions(maxOffset, maxDistance, a, b) {
  // Early termination
  if (a === b)
    return 0;

  const la = a.length,
        lb = b.length;

  if (!la || !lb)
    return Math.max(la, lb);

  let cursorA = 0,
      cursorB = 0,
      longestCommonSubsequence = 0,
      localCommonSubstring = 0;

  while (cursorA < la && cursorB < lb) {
    if (a[cursorA] === b[cursorB]) {
      localCommonSubstring++;
    }
    else {
      longestCommonSubsequence += localCommonSubstring;
      localCommonSubstring = 0;

      if (cursorA !== cursorB)
        cursorA = cursorB = Math.max(cursorA, cursorB);

      for (let i = 0; i < maxOffset && (cursorA + i < la || cursorB + i < lb); i++) {
        if (cursorA + i < la && a[cursorA + i] === b[cursorB]) {
          cursorA += i;
          localCommonSubstring++;
          break;
        }

        if (cursorB + i < lb && a[cursorA] === b[cursorB + i]) {
          cursorB += i;
          localCommonSubstring++;
          break;
        }
      }
    }

    cursorA++;
    cursorB++;

    if (maxDistance) {
      const tempDistance = Math.max(cursorA, cursorB) - longestCommonSubsequence;

      if (tempDistance === maxDistance)
        return maxDistance;

      if (tempDistance > maxDistance)
        return Infinity;
    }
  }

  longestCommonSubsequence += localCommonSubstring;

  return Math.max(la, lb) - longestCommonSubsequence;
}
function withoutTranspositions ( maxOffset , maxDistance , a , b ) { // Early termination if ( a === b ) return 0 ; const la = a . length , lb = b . length ; if ( ! la || ! lb ) return Math . max ( la , lb ) ; let cursorA = 0 , cursorB = 0 , longestCommonSubsequence = 0 , localCommonSubstring = 0 ; while ( cursorA < la && cursorB < lb ) { if ( a [ cursorA ] === b [ cursorB ] ) { localCommonSubstring ++ ; } else { longestCommonSubsequence += localCommonSubstring ; localCommonSubstring = 0 ; if ( cursorA !== cursorB ) cursorA = cursorB = Math . max ( cursorA , cursorB ) ; for ( let i = 0 ; i < maxOffset && ( cursorA + i < la || cursorB + i < lb ) ; i ++ ) { if ( cursorA + i < la && a [ cursorA + i ] === b [ cursorB ] ) { cursorA += i ; localCommonSubstring ++ ; break ; } if ( cursorB + i < lb && a [ cursorA ] === b [ cursorB + i ] ) { cursorB += i ; localCommonSubstring ++ ; break ; } } } cursorA ++ ; cursorB ++ ; if ( maxDistance ) { const tempDistance = Math . max ( cursorA , cursorB ) - longestCommonSubsequence ; if ( tempDistance === maxDistance ) return maxDistance ; if ( tempDistance > maxDistance ) return Infinity ; } } longestCommonSubsequence += localCommonSubstring ; return Math . max ( la , lb ) - longestCommonSubsequence ; }
Simplest version of the SIFT4 algorithm.

@param  {number}       maxOffset   - Search window.
@param  {number}       maxDistance - Maximum distance before exiting.
@param  {string|array} a           - First sequence.
@param  {string|array} b           - Second sequence.
@return {number}                   - The distance.
Simplest version of the SIFT4 algorithm .