UNPKG

@leolee9086/string-metrics-dice

Version:
168 lines (149 loc) 5.11 kB
/** * @typedef {Object} DiceCoefficientOptions * @property {number} [nGramSize=2] - n-gram大小,默认为2(bigram) */ /** * @typedef {Object} DiceCoefficientResult * @property {number} coefficient - Dice系数,范围[0,1] * @property {number} distance - Dice距离,范围[0,1] * @property {string} algorithm - 使用的算法名称 * @property {number} executionTime - 执行时间(毫秒) */ /** * @typedef {Object} AlgorithmMetadata * @property {string} name - 算法名称 * @property {string} version - 算法版本 * @property {Object} complexity - 复杂度信息 * @property {string} complexity.time - 时间复杂度 * @property {string} complexity.space - 空间复杂度 * @property {string[]} characteristics - 算法特征 * @property {string[]} bestFor - 适用场景 * @property {string} author - 作者 */ /** * @typedef {Object} StringDistanceAlgorithm * @property {string} name - 算法名称 * @property {string} version - 算法版本 * @property {function(string, string, DiceCoefficientOptions): number} compute - 计算函数 * @property {AlgorithmMetadata} metadata - 算法元数据 */ /** * 默认的Dice系数计算选项 * @type {DiceCoefficientOptions} */ export const DEFAULT_OPTIONS = { nGramSize: 2 }; /** * 验证Dice系数计算选项 * @param {DiceCoefficientOptions} options - 选项对象 * @returns {DiceCoefficientOptions} 验证后的选项 */ export function validateOptions(options = {}) { const validated = { ...DEFAULT_OPTIONS, ...options }; if (typeof validated.nGramSize !== 'number' || validated.nGramSize < 1) { throw new TypeError('nGramSize must be a positive number'); } return validated; } /** * 预处理字符串 * @param {string} str - 输入字符串 * @param {DiceCoefficientOptions} options - 选项 * @returns {string} 预处理后的字符串 */ export function preprocessString(str, options) { if (typeof str !== 'string') { throw new TypeError('Input must be a string'); } return str; } /** * 生成n-gram集合 * @param {string} str - 输入字符串 * @param {number} nGramSize - n-gram大小 * @returns {Set<string>} n-gram集合 */ export function generateNGrams(str, nGramSize) { const ngrams = new Set(); if (str.length < nGramSize) { return ngrams; } for (let i = 0; i <= str.length - nGramSize; i++) { ngrams.add(str.slice(i, i + nGramSize)); } return ngrams; } /** * 8路循环展开生成n-gram集合 * @param {string} str - 输入字符串 * @param {number} nGramSize - n-gram大小 * @returns {Set<string>} n-gram集合 */ export function generateNGramsUnroll8(str, nGramSize) { const ngrams = new Set(); const len = str.length - nGramSize + 1; let i = 0; // 8路展开 for (; i <= len - 8; i += 8) { ngrams.add(str.slice(i, i + nGramSize)); ngrams.add(str.slice(i + 1, i + 1 + nGramSize)); ngrams.add(str.slice(i + 2, i + 2 + nGramSize)); ngrams.add(str.slice(i + 3, i + 3 + nGramSize)); ngrams.add(str.slice(i + 4, i + 4 + nGramSize)); ngrams.add(str.slice(i + 5, i + 5 + nGramSize)); ngrams.add(str.slice(i + 6, i + 6 + nGramSize)); ngrams.add(str.slice(i + 7, i + 7 + nGramSize)); } // 处理剩余部分 for (; i < len; i++) { ngrams.add(str.slice(i, i + nGramSize)); } return ngrams; } /** * 计算两个集合的交集大小 * @param {Set<string>} set1 - 第一个集合 * @param {Set<string>} set2 - 第二个集合 * @returns {number} 交集大小 */ export function computeIntersectionSize(set1, set2) { let intersectionSize = 0; // 选择较小的集合进行遍历 const [smallerSet, largerSet] = set1.size <= set2.size ? [set1, set2] : [set2, set1]; for (const item of smallerSet) { if (largerSet.has(item)) { intersectionSize++; } } return intersectionSize; } /** * 8路循环展开计算两个集合的交集大小 * @param {Set<string>} set1 - 第一个集合 * @param {Set<string>} set2 - 第二个集合 * @returns {number} 交集大小 */ export function computeIntersectionSizeUnroll8(set1, set2) { let intersectionSize = 0; const [smallerSet, largerSet] = set1.size <= set2.size ? [set1, set2] : [set2, set1]; const arr = Array.from(smallerSet); const len = arr.length; let i = 0; // 8路展开 for (; i <= len - 8; i += 8) { if (largerSet.has(arr[i])) intersectionSize++; if (largerSet.has(arr[i + 1])) intersectionSize++; if (largerSet.has(arr[i + 2])) intersectionSize++; if (largerSet.has(arr[i + 3])) intersectionSize++; if (largerSet.has(arr[i + 4])) intersectionSize++; if (largerSet.has(arr[i + 5])) intersectionSize++; if (largerSet.has(arr[i + 6])) intersectionSize++; if (largerSet.has(arr[i + 7])) intersectionSize++; } // 处理剩余部分 for (; i < len; i++) { if (largerSet.has(arr[i])) intersectionSize++; } return intersectionSize; }