/** * Natural sort utility - Sắp xếp file names theo thứ tự tự nhiên * Ví dụ: file1, file2, file10 (thay vì file1, file10, file2) */ /** * Generate natural sort key for a string * * @param text - String to generate key for * @returns Array of mixed strings and numbers for natural sorting */ export function naturalSortKey(text: string): (string | number)[] { return text .split(/([0-9]+)/) .filter(Boolean) .map(part => { const num = parseInt(part, 10); return isNaN(num) ? part.toLowerCase() : num; }); } /** * Compare two strings using natural sort order * * @param a - First string * @param b - Second string * @returns Negative if a < b, 0 if equal, positive if a > b */ export function naturalSortCompare(a: string, b: string): number { const keyA = naturalSortKey(a); const keyB = naturalSortKey(b); const minLength = Math.min(keyA.length, keyB.length); for (let i = 0; i < minLength; i++) { const partA = keyA[i]; const partB = keyB[i]; if (partA !== partB) { // Both numbers if (typeof partA === 'number' && typeof partB === 'number') { return partA - partB; } // Both strings if (typeof partA === 'string' && typeof partB === 'string') { return partA.localeCompare(partB); } // Number vs string - numbers come first return typeof partA === 'number' ? -1 : 1; } } // All parts equal, shorter string comes first return keyA.length - keyB.length; } /** * Sort array of objects by a property using natural sort * * @param array - Array to sort * @param keyFn - Function to extract sort key from object * @returns Sorted array (new array, not mutated) */ export function naturalSort(array: T[], keyFn: (item: T) => string): T[] { return [...array].sort((a, b) => { const keyA = keyFn(a); const keyB = keyFn(b); return naturalSortCompare(keyA, keyB); }); }