diff --git a/jest-all.config.js b/jest-all.config.js new file mode 100644 index 00000000..d7ad87ae --- /dev/null +++ b/jest-all.config.js @@ -0,0 +1,4 @@ +module.exports = { + name: 'dsa.js', + // testPathIgnorePatterns: ['/node_modules/', '/dist/', '/lab/', '/benchmarks/', '/coverage/'], +}; diff --git a/lab/exercises/10-mixed/document-distance.js b/lab/exercises/10-mixed/document-distance.js new file mode 100644 index 00000000..4c0ca542 --- /dev/null +++ b/lab/exercises/10-mixed/document-distance.js @@ -0,0 +1,23 @@ + +// npx jest lab/exercises/10-mixed/document-distance.spec.js --watch -c 'jest-all.config.js' + +/** + * Find the distance between two documents. + * + * Convert files into vectors of words where the value is the frequency. + * Calculate the angle of the two vectors: cos α = v1 · v2 / |v1| * |v2| + * @param {string} file1 - String of words separated by whitespace + * @param {string} file2 - String of words separated by whitespace + */ +function documentDistance(file1, file2) { + // 0. slip words + // 1. calculate freq of each word per file + const byCounter = (map, w) => map.set(w, 1 + (map.get(w) || 0)); + const f1 = file1.split(' ').reduce(byCounter, new Map()); + const f2 = file2.split(' ').reduce(byCounter, new Map()); + // 2. multiply each occurence and divide it + const dotProd = (m1, m2) => [...new Set([...m1.keys(), ...m2.keys()])].reduce((sum, w) => sum + (m1.get(w) || 0) * (m2.get(w) || 0), 0); + return Math.acos(dotProd(f1, f2) / Math.sqrt(dotProd(f1, f1) * dotProd(f2, f2))); +} + +module.exports = { documentDistance }; diff --git a/lab/exercises/10-mixed/document-distance.spec.js b/lab/exercises/10-mixed/document-distance.spec.js new file mode 100644 index 00000000..67adfb70 --- /dev/null +++ b/lab/exercises/10-mixed/document-distance.spec.js @@ -0,0 +1,20 @@ +const { documentDistance } = require('./document-distance'); + +describe('documentDistance', () => { + it('should work with different files', () => { + const file1 = 'This is a cat.'; + const file2 = 'This is a dog.'; + expect(documentDistance(file1, file2)).toBeCloseTo(0.722); + }); + + it('should work with different files', () => { + const file1 = 'This is a cat.'; + const file2 = 'Occaecat irure enim sint cupidatat id cillum cupidatat ipsum officia ea reprehenderit eiusmod voluptate. Est in laboris esse anim tempor sit in labore eiusmod consectetur aliqua. Quis nulla sunt incididunt magna velit in reprehenderit officia ut esse. Duis proident aute sint laborum consectetur eu reprehenderit amet et esse esse deserunt.'; + expect(documentDistance(file1, file2)).toBeCloseTo(1.57); + }); + + it('should work with equal files', () => { + const file1 = 'This is a cat.'; + expect(documentDistance(file1, file1)).toEqual(0); + }); +});