| | |
| | | // 3.2% that 5 or more groups are invalidated |
| | | |
| | | /** |
| | | * Returns the similarity as number. |
| | | * @param {string} a key |
| | | * @param {string} b key |
| | | * @returns {number} the similarity as number |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Returns the common part and a single char for the difference. |
| | | * @param {string} a key |
| | | * @param {string} b key |
| | | * @param {Set<string>} usedNames set of already used names |
| | |
| | | /** @typedef {Record<string, number>} Sizes */ |
| | | |
| | | /** |
| | | * Adds the provided total to this object. |
| | | * @param {Sizes} total total size |
| | | * @param {Sizes} size single size |
| | | * @returns {void} |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Subtract size from. |
| | | * @param {Sizes} total total size |
| | | * @param {Sizes} size single size |
| | | * @returns {void} |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Returns total size. |
| | | * @template T |
| | | * @param {Iterable<Node<T>>} nodes some nodes |
| | | * @returns {Sizes} total size |
| | | */ |
| | | const sumSize = (nodes) => { |
| | | /** @type {Sizes} */ |
| | | const sum = Object.create(null); |
| | | for (const node of nodes) { |
| | | addSizeTo(sum, node.size); |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Checks whether this object is too big. |
| | | * @param {Sizes} size size |
| | | * @param {Sizes} maxSize minimum size |
| | | * @returns {boolean} true, when size is too big |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Checks whether this object is too small. |
| | | * @param {Sizes} size size |
| | | * @param {Sizes} minSize minimum size |
| | | * @returns {boolean} true, when size is too small |
| | |
| | | return false; |
| | | }; |
| | | |
| | | /** @typedef {Set<string>} Types */ |
| | | |
| | | /** |
| | | * Gets too small types. |
| | | * @param {Sizes} size size |
| | | * @param {Sizes} minSize minimum size |
| | | * @returns {Set<string>} set of types that are too small |
| | | * @returns {Types} set of types that are too small |
| | | */ |
| | | const getTooSmallTypes = (size, minSize) => { |
| | | /** @type {Types} */ |
| | | const types = new Set(); |
| | | for (const key of Object.keys(size)) { |
| | | const s = size[key]; |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Gets number of matching size types. |
| | | * @template {object} T |
| | | * @param {T} size size |
| | | * @param {Set<string>} types types |
| | | * @param {Types} types types |
| | | * @returns {number} number of matching size types |
| | | */ |
| | | const getNumberOfMatchingSizeTypes = (size, types) => { |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Selective size sum. |
| | | * @param {Sizes} size size |
| | | * @param {Set<string>} types types |
| | | * @param {Types} types types |
| | | * @returns {number} selective size sum |
| | | */ |
| | | const selectiveSizeSum = (size, types) => { |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Represents the node runtime component. |
| | | * @template T |
| | | */ |
| | | class Node { |
| | | /** |
| | | * Creates an instance of Node. |
| | | * @param {T} item item |
| | | * @param {string} key key |
| | | * @param {Sizes} size size |
| | |
| | | /** @typedef {number[]} Similarities */ |
| | | |
| | | /** |
| | | * Represents the group runtime component. |
| | | * @template T |
| | | */ |
| | | class Group { |
| | | /** |
| | | * Creates an instance of Group. |
| | | * @param {Node<T>[]} nodes nodes |
| | | * @param {Similarities | null} similarities similarities between the nodes (length = nodes.length - 1) |
| | | * @param {Sizes=} size size of the group |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns removed nodes. |
| | | * @param {(node: Node<T>) => boolean} filter filter function |
| | | * @returns {Node<T>[] | undefined} removed nodes |
| | | */ |
| | | popNodes(filter) { |
| | | /** @type {Node<T>[]} */ |
| | | const newNodes = []; |
| | | /** @type {Similarities} */ |
| | | const newSimilarities = []; |
| | | /** @type {Node<T>[]} */ |
| | | const resultNodes = []; |
| | | /** @type {undefined | Node<T>} */ |
| | | let lastNode; |
| | | for (let i = 0; i < this.nodes.length; i++) { |
| | | const node = this.nodes[i]; |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns similarities. |
| | | * @template T |
| | | * @param {Iterable<Node<T>>} nodes nodes |
| | | * @returns {Similarities} similarities |
| | |
| | | // calculate similarities between lexically adjacent nodes |
| | | /** @type {Similarities} */ |
| | | const similarities = []; |
| | | /** @type {undefined | Node<T>} */ |
| | | let last; |
| | | for (const node of nodes) { |
| | | if (last !== undefined) { |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Defines the shared type used by this module. |
| | | * @template T |
| | | * @typedef {object} GroupedItems<T> |
| | | * @property {string} key |
| | |
| | | */ |
| | | |
| | | /** |
| | | * Defines the options type used by this module. |
| | | * @template T |
| | | * @typedef {object} Options |
| | | * @property {Sizes} maxSize maximum size of a group |
| | |
| | | */ |
| | | |
| | | /** |
| | | * Returns grouped items. |
| | | * @template T |
| | | * @param {Options<T>} options options object |
| | | * @returns {GroupedItems<T>[]} grouped items |
| | |
| | | const initialGroup = new Group(initialNodes, getSimilarities(initialNodes)); |
| | | |
| | | /** |
| | | * Removes problematic nodes. |
| | | * @param {Group<T>} group group |
| | | * @param {Sizes} consideredSize size of the group to consider |
| | | * @returns {boolean} true, if the group was modified |
| | |
| | | // going minSize from left and right |
| | | // at least one node need to be included otherwise we get stuck |
| | | let left = 1; |
| | | /** @type {Sizes} */ |
| | | const leftSize = Object.create(null); |
| | | addSizeTo(leftSize, group.nodes[0].size); |
| | | while (left < group.nodes.length && isTooSmall(leftSize, minSize)) { |
| | |
| | | left++; |
| | | } |
| | | let right = group.nodes.length - 2; |
| | | /** @type {Sizes} */ |
| | | const rightSize = Object.create(null); |
| | | addSizeTo(rightSize, group.nodes[group.nodes.length - 1].size); |
| | | while (right >= 0 && isTooSmall(rightSize, minSize)) { |
| | |
| | | |
| | | if (left - 1 > right) { |
| | | // We try to remove some problematic nodes to "fix" that |
| | | /** @type {Sizes} */ |
| | | let prevSize; |
| | | if (right < group.nodes.length - left) { |
| | | subtractSizeFrom(rightSize, group.nodes[right + 1].size); |
| | |
| | | |
| | | // create two new groups for left and right area |
| | | // and queue them up |
| | | /** @type {Node<T>[]} */ |
| | | const rightNodes = [group.nodes[right + 1]]; |
| | | /** @type {Similarities} */ |
| | | const rightSimilarities = []; |
| | |
| | | } |
| | | queue.push(new Group(rightNodes, rightSimilarities)); |
| | | |
| | | /** @type {Node<T>[]} */ |
| | | const leftNodes = [group.nodes[0]]; |
| | | /** @type {Similarities} */ |
| | | const leftSimilarities = []; |
| | |
| | | }); |
| | | |
| | | // give every group a name |
| | | /** @type {Set<string>} */ |
| | | const usedNames = new Set(); |
| | | for (let i = 0; i < result.length; i++) { |
| | | const group = result[i]; |