diff --git a/bin/performance.js b/bin/performance.js index b64a088..33c3378 100644 --- a/bin/performance.js +++ b/bin/performance.js @@ -1,8 +1,9 @@ +"use strict" const LTT = require('../dist/old/list-to-tree.npm.js'); const LTT1 = require('../dist/list-to-tree.js'); const IronTree = require('@denq/iron-tree'); -const LENGTH = 20000; +const LENGTH = 25000; function getList() { @@ -29,8 +30,12 @@ function performanceCalc(fn, ...params) { console.log(`Result: ${result}. Execution Time: ${end - start} ms`) } +const list = getList(); +const xlist = list.map(item => Object.assign({}, item)); + function runListToTree() { - var ltt = new LTT(getList(), { + // const _list = Array(list.length).fill().map((item, index) => list[index]); + var ltt = new LTT(xlist, { key_id: 'id', key_parent: 'parent', key_child: 'children', @@ -41,7 +46,7 @@ function runListToTree() { function runIronTree() { const tree = new IronTree({ id: 0 }); - getList().forEach((item, index) => { + list.forEach((item, index) => { tree.add((parentNode) => { return parentNode.get('id') === item.parent; }, item); @@ -53,10 +58,11 @@ function runIronTree() { } function runNewListToTree() { - const ltt = new LTT1(getList(), { + const ltt = new LTT1(list, { key_id: 'id', key_parent: 'parent', key_child: 'children', + many_items: true, }); var tree = ltt.GetTree(); return 'new list-to-tree'; diff --git a/dist/list-to-tree.js b/dist/list-to-tree.js index 87f9f74..0d27dd5 100644 --- a/dist/list-to-tree.js +++ b/dist/list-to-tree.js @@ -1,26 +1,13 @@ const IronTree = require('@denq/iron-tree'); +const sortBy = require('../utils/sort-by'); +const compareById = require('../utils/compare-by-id'); const defaultOptions = { key_id: 'id' , key_parent: 'parent' , key_child: 'child', empty_children: false, -}; - -function sortBy(collection, propertyA, propertyB) { - return collection.sort(function(a, b) { - if (a[propertyB] < b[propertyB]) { - if (a[propertyA] > b[propertyA]) { - return 1; - } - return -1; - } else { - if (a[propertyA] < b[propertyA]) { - return -1; - } - return 1; - } - }); + many_items: false, }; module.exports = class LTT{ @@ -30,29 +17,87 @@ module.exports = class LTT{ options = Object.assign({}, defaultOptions, options); this.options = options; - const { key_id, key_parent } = options; - sortBy(_list, key_parent, key_id); + if (options.many_items) { + const collections = this.split(_list); + this.tree = collections.map((item) => { + return this.buildTreeFromList(item); + }); + } else { + this.tree = this.buildTreeFromList(_list); + } + } + + buildTreeFromList(list) { + const { key_id, key_parent } = this.options; + + sortBy(list, key_parent, key_id); const tree = new IronTree({ [key_id]: 0 }); - _list.forEach((item, index) => { + list.forEach((item, index) => { tree.add((parentNode) => { return parentNode.get(key_id) === item[key_parent]; }, item); }); - - this.tree = tree; + return tree; } sort(criteria) { - this.tree.sort(criteria); + const { many_items } = this.options; + if (many_items) { + this.tree.forEach((item) => { + item.sort(criteria); + }); + //hack + this.tree = this.tree.map((item) => { + const id = item.rootNode.children[0].get('id') + item.set('id', id); + item.set('xid', id); + return item; + }); + this.tree.sort(criteria); + // end hack + } else { + this.tree.sort(criteria); + } + } + + split(list) { + const { key_id, key_parent } = this.options; + + list.sort(compareById(true, key_parent)); + const rootParentId = list[0][key_parent]; + + const collection = []; + list.forEach((item) => { + if (item[key_parent] === rootParentId) { + collection.push([item]); + } else { + collection.forEach((el) => { + el.forEach((child) => { + if (child[key_id] === item[key_parent]) { + el.push(item); + } + }); + }); + + } + }); + return collection; } GetTree() { - const { key_child, empty_children } = this.options; - return this.tree.toJson({ - key_children: key_child, - empty_children: false, - })[key_child]; + const { key_child, empty_children, many_items } = this.options; + if (many_items) { + const trees = this.tree.map((item) => { + return item.toJson(this.options).children[0]; + }); + return [].concat(...trees); + } else { + return this.tree.toJson({ + key_children: key_child, + empty_children: false, + })[key_child]; + } } } diff --git a/package-lock.json b/package-lock.json index 0ef1c54..82f509c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,13 @@ { "name": "list-to-tree", - "version": "2.1.0", + "version": "2.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@denq/iron-tree": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@denq/iron-tree/-/iron-tree-1.2.0.tgz", - "integrity": "sha512-xLjz/wKxPoI6XhwRWZDtdBJyx0CrrkrqqT+7iKmlLW3oIHaWDU7m/gTNrToxu469yH0RtwXOcqpE8dDIEEVAaw==" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@denq/iron-tree/-/iron-tree-1.3.0.tgz", + "integrity": "sha512-vc4yrcynR1T9ttEIh1rMkPvXpF2XNfYGJIL1ucs8A+Xka0NEU+4wQW7OyR4N+VgYUfArfsqD+dNTkyRhDL55mQ==" }, "balanced-match": { "version": "1.0.0", diff --git a/package.json b/package.json index 1e0604d..8131f0e 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,6 @@ "jasmine": "^2.8.0" }, "dependencies": { - "@denq/iron-tree": "^1.2.0" + "@denq/iron-tree": "^1.3.0" } } diff --git a/spec/split-spec.js b/spec/split-spec.js new file mode 100644 index 0000000..dc92102 --- /dev/null +++ b/spec/split-spec.js @@ -0,0 +1,88 @@ +require("util").inspect.defaultOptions.depth = null; +const LTT = require('../dist/list-to-tree'); + +function compareById(vector) { + return (a, b) => { + const aid = Number(a.get('id')); + const bid = Number(b.get('id')); + if (aid > bid) { + return vector ? 1 : -1; + } else if (aid < bid) { + return vector ? -1 : 1; + } else { + return 0 + } + }; +} + +const key_id = 'id'; +const key_parent = 'parent'; +const key_child = 'child'; +const many_items = true; + +const list = [ + { id: 1, parent: 0 }, + { id: 2, parent: 0 }, + { id: 3, parent: 2 }, + { id: 4, parent: 3 }, + { id: 5, parent: 2 }, + { id: 6, parent: 1 }, + { id: 7, parent: 0 }, + { id: 8, parent: 7 }, + { id: 9, parent: 7 }, + { id: 10, parent: 8 }, + { id: 11, parent: 6 }, + { id: 12, parent: 0 }, +]; +const ltt = new LTT(list, { + key_id, + key_parent, + key_child, + many_items, +}); +ltt.sort(compareById(true)); + +describe('Split', function() { + + it('Run method - split', function() { + const collection = ltt.split(list); + expect(collection.length).toBe(4); + + expect(collection[0][0].id).toBe(7); + expect(collection[0][1].id).toBe(8); + expect(collection[0][2].id).toBe(9); + expect(collection[0][3].id).toBe(10); + + expect(collection[1][0].id).toBe(1); + expect(collection[1][1].id).toBe(6); + expect(collection[1][2].id).toBe(11); + + expect(collection[2][0].id).toBe(2); + expect(collection[2][1].id).toBe(5); + expect(collection[2][2].id).toBe(3); + expect(collection[2][3].id).toBe(4); + + expect(collection[3][0].id).toBe(12); + }); + + it('GetTree', function() { + const tree = ltt.GetTree(); + + expect(tree[0].id).toBe(1); + expect(tree[0].children[0].id).toBe(6); + expect(tree[0].children[0].children[0].id).toBe(11); + + expect(tree[1].id).toBe(2); + expect(tree[1].children[0].id).toBe(3); + expect(tree[1].children[0].children[0].id).toBe(4); + expect(tree[1].children[1].id).toBe(5); + + expect(tree[2].id).toBe(7); + expect(tree[2].children[0].id).toBe(8); + expect(tree[2].children[0].children[0].id).toBe(10); + expect(tree[2].children[1].id).toBe(9); + + expect(tree[3].id).toBe(12); + }); + +}) diff --git a/utils/compare-by-id.js b/utils/compare-by-id.js new file mode 100644 index 0000000..d8d8394 --- /dev/null +++ b/utils/compare-by-id.js @@ -0,0 +1,13 @@ +module.exports = function compareById(vector, key) { + return (a, b) => { + const aid = Number(a[key]); + const bid = Number(b[key]); + if (aid > bid) { + return vector ? 1 : -1; + } else if (aid < bid) { + return vector ? -1 : 1; + } else { + return 0 + } + }; +} diff --git a/utils/sort-by.js b/utils/sort-by.js new file mode 100644 index 0000000..5bf9d47 --- /dev/null +++ b/utils/sort-by.js @@ -0,0 +1,15 @@ +module.exports = function sortBy(collection, propertyA, propertyB) { + return collection.sort(function(a, b) { + if (a[propertyB] < b[propertyB]) { + if (a[propertyA] > b[propertyA]) { + return 1; + } + return -1; + } else { + if (a[propertyA] < b[propertyA]) { + return -1; + } + return 1; + } + }); +}