/** * Calculate Levenshtein distance between two strings * @param {string} str1 - First string * @param {string} str2 - Second string * @returns {number} - Edit distance */ function levenshteinDistance(str1, str2) { const len1 = str1.length; const len2 = str2.length; const matrix = Array(len1 + 1).fill(null).map(() => Array(len2 + 1).fill(0)); for (let i = 0; i <= len1; i++) matrix[i][0] = i; for (let j = 0; j <= len2; j++) matrix[0][j] = j; for (let i = 1; i <= len1; i++) { for (let j = 1; j <= len2; j++) { const cost = str1[i - 1] === str2[j - 1] ? 0 : 1; matrix[i][j] = Math.min( matrix[i - 1][j] + 1, // deletion matrix[i][j - 1] + 1, // insertion matrix[i - 1][j - 1] + cost // substitution ); } } return matrix[len1][len2]; } /** * Calculate similarity percentage between two strings (0-100%) * @param {string} str1 - First string * @param {string} str2 - Second string * @returns {number} - Similarity percentage */ export function calculateSimilarity(str1, str2) { const lower1 = str1.toLowerCase().trim(); const lower2 = str2.toLowerCase().trim(); if (lower1 === lower2) return 100; if (lower1.length === 0 || lower2.length === 0) return 0; const distance = levenshteinDistance(lower1, lower2); const maxLength = Math.max(lower1.length, lower2.length); const similarity = ((maxLength - distance) / maxLength) * 100; return Math.round(similarity); } /** * Find items with similarity >= threshold * @param {string} inputName - Item name to check * @param {Array} existingItems - Array of existing items with item_name property * @param {number} threshold - Minimum similarity percentage (default 80) * @returns {Array} - Array of similar items sorted by similarity */ export function findSimilarItems(inputName, existingItems, threshold = 80) { const similar = []; for (const item of existingItems) { const similarity = calculateSimilarity(inputName, item.item_name); if (similarity >= threshold && similarity < 100) { similar.push({ ...item, similarity }); } } // Sort by similarity descending return similar.sort((a, b) => b.similarity - a.similarity); }