UNPKG

@leolee9086/string-metrics-dice

Version:
123 lines (118 loc) 4.1 kB
import { validateOptions, preprocessString } from './schema.js'; /** * 8路循环展开生成n-gram集合 * @param {string} str - 输入字符串 * @param {number} nGramSize - n-gram大小 * @returns {Set<string>} n-gram集合 */ 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; } /** * 8路循环展开计算两个集合的交集大小 * @param {Set<string>} set1 - 第一个集合 * @param {Set<string>} set2 - 第二个集合 * @returns {number} 交集大小 */ 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; } /** * 8路循环展开Sørensen-Dice系数算法实现 * * 算法原理同basic.js,但n-gram生成和交集计算采用8路循环展开 * * @param {string} str1 - 第一个字符串 * @param {string} str2 - 第二个字符串 * @param {import('./schema.js').DiceCoefficientOptions} options - 计算选项 * @returns {number} Dice系数,范围[0,1] */ export function computeDiceCoefficientUnroll8(str1, str2, options = {}) { const validatedOptions = validateOptions(options); // 预处理字符串 const processedStr1 = preprocessString(str1, validatedOptions); const processedStr2 = preprocessString(str2, validatedOptions); // 生成n-gram集合(8路展开) const ngrams1 = generateNGramsUnroll8(processedStr1, validatedOptions.nGramSize); const ngrams2 = generateNGramsUnroll8(processedStr2, validatedOptions.nGramSize); // 计算交集大小(8路展开) const intersectionSize = computeIntersectionSizeUnroll8(ngrams1, ngrams2); // 计算Dice系数 const totalSize = ngrams1.size + ngrams2.size; if (totalSize === 0) { return 0; } return (2 * intersectionSize) / totalSize; } /** * 计算Dice距离(1 - Dice系数) * @param {string} str1 - 第一个字符串 * @param {string} str2 - 第二个字符串 * @param {import('./schema.js').DiceCoefficientOptions} options - 计算选项 * @returns {number} Dice距离,范围[0,1] */ export function computeDiceDistanceUnroll8(str1, str2, options = {}) { const coefficient = computeDiceCoefficientUnroll8(str1, str2, options); return 1 - coefficient; } /** * 算法元数据 */ export const metadata = { name: 'Unroll8 Sørensen-Dice', version: '1.0.0', complexity: { time: 'O(n)', space: 'O(n)' }, characteristics: [ '8路循环展开', '批量处理', '适合大数据', '高性能优化' ], bestFor: [ '长字符串比较', '高性能要求', '大规模数据处理' ], author: '织' };