Repository: plexis-js/plexis (js)

Issue:
Feature request: `distance`
This method calculates the [Levenshtein Distance](https://en.wikipedia.org/wiki/Levenshtein_distance)  between two strings.

```javascript
@param {String} [fromStr]
@param {String} [toStr]
@returns {Number} The Levenshtein distance
```

**Example usage**

```javascript
import distance from '@plexis/distance';
distance('book', ''back') // => 2
distance('black', 'back') // => 1
distance('Foo', 'Bar') // => 3
```

**Aliases**

```javascript
import distance from '@plexis/distance';
import {distance, calcLevenshtein, levenshtein} from 'plexis';
```

Pull request:
feat: distance closes #5
Hi.

This is for #5 .

Brandon

Patch:
diff --git a/docs/pages/api.md b/docs/pages/api.md
index 5b3aec5..4ec41de 100644
--- a/docs/pages/api.md
+++ b/docs/pages/api.md
@@ -2,6 +2,7 @@
 
 - [cache](/packages/cache)
 - [compose](/packages/compose)
+- [distance](/packages/distance)
 - [isLowerCase](/packages/isLowerCase)
 - [isUpperCase](/packages/isUpperCase)
 - [startsWith](/packages/startsWith)
diff --git a/packages/distance/README.md b/packages/distance/README.md
new file mode 100644
index 0000000..33fc67a
--- /dev/null
+++ b/packages/distance/README.md
@@ -0,0 +1,21 @@
+## `distance`
+
+Calculates the [Levenshtein Distance](https://en.wikipedia.org/wiki/Levenshtein_distance) between two strings.
+
+`npm i @plexis/distance`
+
+**Usage**
+
+```javascript
+import distance from '@plexis/distance';
+distance('book', 'back'); // returns 2
+distance('black', 'back'); // returns 1
+distance('Foo', 'Bar'); // returns 3
+```
+
+**Aliases**
+
+```javascript
+import distance from '@plexis/distance';
+import {distance, calcLevenshtein, levenshtein} from 'plexis';
+```
diff --git a/packages/distance/package.json b/packages/distance/package.json
new file mode 100644
index 0000000..676f6fb
--- /dev/null
+++ b/packages/distance/package.json
@@ -0,0 +1,27 @@
+{
+  "name": "@plexis/distance",
+  "version": "0.0.14",
+  "main": "dist/index.js",
+  "module": "dist/index.esm.js",
+  "jsnext:main": "./src/index.js",
+  "files": [
+    "dist", 
+    "src"
+  ],
+  "author": "Brandon Skinner <brandon.m.skinner@gmail.com>",
+  "license": "MIT",
+  "keywords": [
+    "utility",
+    "string",
+    "parse",
+    "format",
+    "validate"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/plexis-js/plexis.git"
+  },
+  "publishConfig": {
+    "access": "public"
+  }
+}
\ No newline at end of file
diff --git a/packages/distance/src/index.js b/packages/distance/src/index.js
new file mode 100644
index 0000000..bbe7688
--- /dev/null
+++ b/packages/distance/src/index.js
@@ -0,0 +1,47 @@
+/**
+ * @description Calculates the Levenshtein Distance toStretween two strings
+ * @param {String} [fromStr]
+ * @param {String} [toStr]
+ * @returns {Number} The Levenshtein distance
+ * @example
+ * distance('book', 'back') // returns 2
+ * distance('black', 'back') // returns 1
+ * distance('Foo', 'Bar') // returns 3
+ */
+const distance = (fromStr, toStr) => {
+  if (typeof fromStr !== 'string' || typeof toStr !== 'string') return 0;
+  if (fromStr.length === 0) return toStr.length;
+  if (toStr.length === 0) return fromStr.length;
+
+  if (fromStr.length > toStr.length) {
+    let tmp = fromStr;
+    fromStr = toStr;
+    toStr = tmp;
+  }
+
+  let row = Array(fromStr.length);
+  let i;
+  let prev;
+  let val;
+
+  for (i = 0; i <= fromStr.length; i++) {
+    row[i] = i;
+  }
+
+  for (i = 1; i <= toStr.length; i++) {
+    prev = i;
+    for (var j = 1; j <= fromStr.length; j++) {
+      if (toStr[i - 1] === fromStr[j - 1]) {
+        val = row[j - 1];
+      } else {
+        val = Math.min(row[j - 1] + 1, prev + 1, row[j] + 1);
+      }
+      row[j - 1] = prev;
+      prev = val;
+    }
+    row[fromStr.length] = prev;
+  }
+  return row[fromStr.length];
+};
+
+export default distance;
diff --git a/packages/plexis/package.json b/packages/plexis/package.json
index 7e55d13..2e2cc82 100644
--- a/packages/plexis/package.json
+++ b/packages/plexis/package.json
@@ -14,6 +14,7 @@
   "license": "MIT",
   "dependencies": {
     "@plexis/compose": "^0.0.14",
+    "@plexis/distance": "^0.0.14",
     "@plexis/is-lowercase": "^0.0.14",
     "@plexis/is-uppercase": "^0.0.14",
     "@plexis/starts-with": "^0.0.14",
diff --git a/packages/plexis/src/index.js b/packages/plexis/src/index.js
index cd5f0ee..802c19b 100644
--- a/packages/plexis/src/index.js
+++ b/packages/plexis/src/index.js
@@ -21,4 +21,9 @@ export {
   default as toChicagoTitle
 } from '@plexis/to-chicago';
 export {default as startsWith} from '@plexis/starts-with';
+export {
+  default as distance,
+  default as calcLevenshtein,
+  default as levenshtein
+} from '@plexis/distance';
 export {default as isString} from '@plexis/is-string';


Test patch:
diff --git a/packages/distance/test/index.js b/packages/distance/test/index.js
new file mode 100644
index 0000000..143b7f0
--- /dev/null
+++ b/packages/distance/test/index.js
@@ -0,0 +1,28 @@
+import distance from '../src';
+
+it('Should calculate Levenshtein Distance between two strings', () => {
+  expect(distance('book', 'back')).toBe(2);
+  expect(distance('black', 'back')).toBe(1);
+  expect(distance('Foo', 'Bar')).toBe(3);
+  expect(distance('cool', 'cool')).toBe(0);
+  expect(distance('There was a black cat', 'There was a black dog')).toBe(3);
+  expect(distance('!@#$', '!@#$')).toBe(0);
+  expect(distance('<table>', '<td>')).toBe(4);
+});
+
+it('Levenshtein Distance should be the same for the same strings', () => {
+  expect(distance('flaw', 'lawn')).toBe(2);
+  expect(distance('lawn', 'flaw')).toBe(2);
+  expect(distance('encyclopedia', 'cat')).toBe(11);
+  expect(distance('cat', 'encyclopedia')).toBe(11);
+});
+
+it('Should return a Levenshtein Distance of 0 for non-strings', () => {
+  expect(distance(x => 0, 'back')).toBe(0);
+  expect(distance(9, 'back')).toBe(0);
+  expect(distance(45, 0)).toBe(0);
+});
+
+it('Should return a number', () => {
+  expect(typeof distance('book', 'back')).toBe('number');
+});
diff --git a/packages/plexis/test/__snapshots__/index.js.snap b/packages/plexis/test/__snapshots__/index.js.snap
index d971372..b101624 100644
--- a/packages/plexis/test/__snapshots__/index.js.snap
+++ b/packages/plexis/test/__snapshots__/index.js.snap
@@ -26,6 +26,9 @@ Array [
   "toChicagoStyle",
   "toChicagoTitle",
   "startsWith",
+  "distance",
+  "calcLevenshtein",
+  "levenshtein",
   "isString",
 ]
 `;