diff --git a/src/data-structures/bloom-filter/BloomFilter.js b/src/data-structures/bloom-filter/BloomFilter.js index 465e6f58..652c0d73 100644 --- a/src/data-structures/bloom-filter/BloomFilter.js +++ b/src/data-structures/bloom-filter/BloomFilter.js @@ -1,6 +1,6 @@ export default class BloomFilter { /** - * @param {number} size + * @param {number} size - the size of the storage. */ constructor(size = 100) { // Bloom filter size directly affects the likelihood of false positives. @@ -15,7 +15,7 @@ export default class BloomFilter { insert(item) { const hashValues = this.getHashValues(item); - // Set each hashValue index to true + // Set each hashValue index to true. hashValues.forEach(val => this.storage.setValue(val)); } @@ -26,8 +26,8 @@ export default class BloomFilter { mayContain(item) { const hashValues = this.getHashValues(item); - for (let i = 0; i < hashValues.length; i += 1) { - if (!this.storage.getValue(hashValues[i])) { + for (let hashIndex = 0; hashIndex < hashValues.length; hashIndex += 1) { + if (!this.storage.getValue(hashValues[hashIndex])) { // We know that the item was definitely not inserted. return false; } @@ -50,7 +50,7 @@ export default class BloomFilter { const storage = []; // Initialize all indexes to false - for (let i = 0; i < size; i += 1) { + for (let storageCellIndex = 0; storageCellIndex < size; storageCellIndex += 1) { storage.push(false); } @@ -67,14 +67,14 @@ export default class BloomFilter { } /** - * @param {string} str + * @param {string} item * @return {number} */ - hash1(str) { + hash1(item) { let hash = 0; - for (let i = 0; i < str.length; i += 1) { - const char = str.charCodeAt(i); + for (let charIndex = 0; charIndex < item.length; charIndex += 1) { + const char = item.charCodeAt(charIndex); hash = (hash << 5) + hash + char; hash &= hash; // Convert to 32bit integer hash = Math.abs(hash); @@ -84,44 +84,48 @@ export default class BloomFilter { } /** - * @param {string} str + * @param {string} item * @return {number} */ - hash2(str) { + hash2(item) { let hash = 5381; - for (let i = 0; i < str.length; i += 1) { - const char = str.charCodeAt(i); + for (let charIndex = 0; charIndex < item.length; charIndex += 1) { + const char = item.charCodeAt(charIndex); hash = (hash << 5) + hash + char; /* hash * 33 + c */ } - return hash % this.size; + return Math.abs(hash % this.size); } /** - * @param {string} str + * @param {string} item * @return {number} */ - hash3(str) { + hash3(item) { let hash = 0; - for (let i = 0; i < str.length; i += 1) { - const char = str.charCodeAt(i); + for (let charIndex = 0; charIndex < item.length; charIndex += 1) { + const char = item.charCodeAt(charIndex); hash = (hash << 5) - hash; hash += char; hash &= hash; // Convert to 32bit integer } - return hash % this.size; + return Math.abs(hash % this.size); } /** - * Runs all 3 hash functions on the input and returns an array of results + * Runs all 3 hash functions on the input and returns an array of results. * - * @param {string} str + * @param {string} item * @return {number[]} */ getHashValues(item) { - return [this.hash1(item), Math.abs(this.hash2(item)), Math.abs(this.hash3(item))]; + return [ + this.hash1(item), + this.hash2(item), + this.hash3(item), + ]; } } diff --git a/src/data-structures/bloom-filter/__test__/BloomFilter.test.js b/src/data-structures/bloom-filter/__test__/BloomFilter.test.js index a8b9c233..1299f983 100644 --- a/src/data-structures/bloom-filter/__test__/BloomFilter.test.js +++ b/src/data-structures/bloom-filter/__test__/BloomFilter.test.js @@ -1,39 +1,62 @@ import BloomFilter from '../BloomFilter'; -describe('Bloom Filter', () => { +describe('BloomFilter', () => { let bloomFilter; - const people = ['Bruce Wayne', 'Clark Kent', 'Barry Allen']; + const people = [ + 'Bruce Wayne', + 'Clark Kent', + 'Barry Allen', + ]; beforeEach(() => { bloomFilter = new BloomFilter(); }); - it('Should have methods named "insert" and "mayContain"', () => { + it('should have methods named "insert" and "mayContain"', () => { expect(typeof bloomFilter.insert).toBe('function'); expect(typeof bloomFilter.mayContain).toBe('function'); }); - it('Should create a new filter store with the appropriate methods', () => { + it('should create a new filter store with the appropriate methods', () => { const store = bloomFilter.createStore(18); expect(typeof store.getValue).toBe('function'); expect(typeof store.setValue).toBe('function'); }); - it('Should hash deterministically with all 3 hash functions', () => { - const str = 'abc'; - expect(bloomFilter.hash1(str)).toEqual(bloomFilter.hash1(str)); - expect(bloomFilter.hash2(str)).toEqual(bloomFilter.hash2(str)); - expect(bloomFilter.hash3(str)).toEqual(bloomFilter.hash3(str)); + it('should hash deterministically with all 3 hash functions', () => { + const str1 = 'apple'; + + expect(bloomFilter.hash1(str1)).toEqual(bloomFilter.hash1(str1)); + expect(bloomFilter.hash2(str1)).toEqual(bloomFilter.hash2(str1)); + expect(bloomFilter.hash3(str1)).toEqual(bloomFilter.hash3(str1)); + + expect(bloomFilter.hash1(str1)).toBe(14); + expect(bloomFilter.hash2(str1)).toBe(43); + expect(bloomFilter.hash3(str1)).toBe(10); + + const str2 = 'orange'; + + expect(bloomFilter.hash1(str2)).toEqual(bloomFilter.hash1(str2)); + expect(bloomFilter.hash2(str2)).toEqual(bloomFilter.hash2(str2)); + expect(bloomFilter.hash3(str2)).toEqual(bloomFilter.hash3(str2)); + + expect(bloomFilter.hash1(str2)).toBe(0); + expect(bloomFilter.hash2(str2)).toBe(61); + expect(bloomFilter.hash3(str2)).toBe(10); }); - it('Should create an array with 3 hash values', () => { - expect(bloomFilter.getHashValues('abc').length).toEqual(3); + it('should create an array with 3 hash values', () => { + expect(bloomFilter.getHashValues('abc').length).toBe(3); + expect(bloomFilter.getHashValues('abc')).toEqual([66, 63, 54]); }); - it('Should insert strings correctly and return true when checking for inserted values', () => { + it('should insert strings correctly and return true when checking for inserted values', () => { people.forEach(person => bloomFilter.insert(person)); - expect(bloomFilter.mayContain('Bruce Wayne')).toBe(true); - expect(bloomFilter.mayContain('Clark Kent')).toBe(true); - expect(bloomFilter.mayContain('Barry Allen')).toBe(true); + + expect(bloomFilter.mayContain('Bruce Wayne')).toBeTruthy(); + expect(bloomFilter.mayContain('Clark Kent')).toBeTruthy(); + expect(bloomFilter.mayContain('Barry Allen')).toBeTruthy(); + + expect(bloomFilter.mayContain('Tony Stark')).toBeFalsy(); }); });