Merge pull request #122 from sachaaaaa/consolidateLists
Add logic to consolidate list of data returned by different snodespull/126/head
						commit
						4b4a2b1bf2
					
				@ -0,0 +1,35 @@
 | 
			
		||||
/* global window */
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line func-names
 | 
			
		||||
(function () {
 | 
			
		||||
  window.libloki = window.libloki || {};
 | 
			
		||||
  window.libloki.serviceNodes = window.libloki.serviceNodes || {};
 | 
			
		||||
 | 
			
		||||
  function consolidateLists(lists, threshold = 1){
 | 
			
		||||
    if (typeof threshold !== 'number') {
 | 
			
		||||
      throw Error('Provided threshold is not a number');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // calculate list size manually since `Set`
 | 
			
		||||
    // does not have a `length` attribute
 | 
			
		||||
    let numLists = 0;
 | 
			
		||||
    const occurences = {};
 | 
			
		||||
    lists.forEach(list => {
 | 
			
		||||
      numLists += 1;
 | 
			
		||||
      list.forEach(item => {
 | 
			
		||||
        if (!(item in occurences)) {
 | 
			
		||||
          occurences[item] = 1;
 | 
			
		||||
        } else {
 | 
			
		||||
          occurences[item] += 1;
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const scaledThreshold = numLists * threshold;
 | 
			
		||||
    return Object.entries(occurences)
 | 
			
		||||
      .filter(keyValue => keyValue[1] >= scaledThreshold)
 | 
			
		||||
      .map(keyValue => keyValue[0]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  window.libloki.serviceNodes.consolidateLists = consolidateLists;
 | 
			
		||||
})();
 | 
			
		||||
@ -0,0 +1,57 @@
 | 
			
		||||
/* global libloki, chai */
 | 
			
		||||
 | 
			
		||||
describe('ServiceNodes', () => {
 | 
			
		||||
  describe('#consolidateLists', () => {
 | 
			
		||||
    it('should throw when provided a non-iterable list', () => {
 | 
			
		||||
      chai.expect(() => libloki.serviceNodes.consolidateLists(null, 1)).to.throw();
 | 
			
		||||
    });
 | 
			
		||||
    it('should throw when provided a non-iterable item in the list', () => {
 | 
			
		||||
      chai.expect(() => libloki.serviceNodes.consolidateLists([1, 2, 3], 1)).to.throw();
 | 
			
		||||
    });
 | 
			
		||||
    it('should throw when provided a non-number threshold', () => {
 | 
			
		||||
      chai.expect(() => libloki.serviceNodes.consolidateLists([], 'a')).to.throw();
 | 
			
		||||
    });
 | 
			
		||||
    it('should return an empty array when the input is an empty array', () => {
 | 
			
		||||
      const result = libloki.serviceNodes.consolidateLists([]);
 | 
			
		||||
      chai.expect(result).to.deep.equal([]);
 | 
			
		||||
    });
 | 
			
		||||
    it('should return the input when only 1 list is provided', () => {
 | 
			
		||||
      const result = libloki.serviceNodes.consolidateLists([['a', 'b', 'c']]);
 | 
			
		||||
      chai.expect(result).to.deep.equal(['a', 'b', 'c']);
 | 
			
		||||
    });
 | 
			
		||||
    it('should return the union of all lists when threshold is 0', () => {
 | 
			
		||||
      const result = libloki.serviceNodes.consolidateLists([
 | 
			
		||||
        ['a', 'b', 'c', 'h'],
 | 
			
		||||
        ['d', 'e', 'f', 'g'],
 | 
			
		||||
        ['g', 'h'],
 | 
			
		||||
      ], 0);
 | 
			
		||||
      chai.expect(result.sort()).to.deep.equal(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
 | 
			
		||||
    });
 | 
			
		||||
    it('should return the intersection of all lists when threshold is 1', () => {
 | 
			
		||||
      const result = libloki.serviceNodes.consolidateLists([
 | 
			
		||||
        ['a', 'b', 'c', 'd'],
 | 
			
		||||
        ['a', 'e', 'f', 'g'],
 | 
			
		||||
        ['a', 'h'],
 | 
			
		||||
      ], 1);
 | 
			
		||||
      chai.expect(result).to.deep.equal(['a']);
 | 
			
		||||
    });
 | 
			
		||||
    it('should return the elements that have an occurence >= the provided threshold', () => {
 | 
			
		||||
      const result = libloki.serviceNodes.consolidateLists([
 | 
			
		||||
        ['a', 'b', 'c', 'd', 'e', 'f', 'g'],
 | 
			
		||||
        ['a', 'b', 'c', 'd', 'e', 'f', 'h'],
 | 
			
		||||
        ['a', 'b', 'c', 'd', 'e', 'f', 'g'],
 | 
			
		||||
        ['a', 'b', 'c', 'd', 'e', 'g', 'h'],
 | 
			
		||||
      ], 3/4);
 | 
			
		||||
      chai.expect(result).to.deep.equal(['a', 'b', 'c', 'd', 'e', 'f', 'g']);
 | 
			
		||||
    });
 | 
			
		||||
    it('should work with sets as well', () => {
 | 
			
		||||
      const result = libloki.serviceNodes.consolidateLists(new Set([
 | 
			
		||||
        new Set(['a', 'b', 'c', 'd', 'e', 'f', 'g']),
 | 
			
		||||
        new Set(['a', 'b', 'c', 'd', 'e', 'f', 'h']),
 | 
			
		||||
        new Set(['a', 'b', 'c', 'd', 'e', 'f', 'g']),
 | 
			
		||||
        new Set(['a', 'b', 'c', 'd', 'e', 'g', 'h']),
 | 
			
		||||
      ]), 3/4);
 | 
			
		||||
      chai.expect(result).to.deep.equal(['a', 'b', 'c', 'd', 'e', 'f', 'g']);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
					Loading…
					
					
				
		Reference in New Issue