[{"data":1,"prerenderedAt":817},["ShallowReactive",2],{"guide-natural-sort-vs-lexicographic":3},{"id":4,"title":5,"body":6,"date":809,"description":810,"extension":811,"meta":812,"navigation":177,"path":813,"readingTime":458,"seo":814,"stem":815,"__hash__":816},"guides\u002Fguides\u002Fnatural-sort-vs-lexicographic.md","Natural Sort vs Lexicographic Sort",{"type":7,"value":8,"toc":802},"minimark",[9,22,27,38,48,65,68,138,142,145,151,154,227,231,250,266,279,299,303,306,709,730,775,779,790,798],[10,11,12,13,17,18,21],"p",{},"If you have ever sorted a list of files and seen ",[14,15,16],"code",{},"file1.txt, file10.txt, file2.txt"," instead of the expected ",[14,19,20],{},"file1.txt, file2.txt, file10.txt",", you have encountered the difference between lexicographic and natural sorting. Lexicographic (alphabetical) sorting compares characters one by one, treating digits like any other character. Natural sorting recognizes numeric sequences and compares them as whole numbers. The distinction matters whenever your data contains mixed text and numbers.",[23,24,26],"h2",{"id":25},"how-lexicographic-sort-works","How Lexicographic Sort Works",[10,28,29,30,33,34,37],{},"Lexicographic sorting compares strings character by character based on each character's code point value. When comparing ",[14,31,32],{},"file10"," and ",[14,35,36],{},"file2",", the algorithm proceeds as follows:",[39,40,45],"pre",{"className":41,"code":43,"language":44},[42],"language-text","file10 vs file2\n──────       (f = f, continue)\n ─────       (i = i, continue)\n  ────       (l = l, continue)\n   ───       (e = e, continue)\n    ──       (1 vs 2 → '1' (49) \u003C '2' (50)) → file10 comes first\n","text",[14,46,43],{"__ignoreMap":47},"",[10,49,50,51,54,55,58,59,61,62,64],{},"The digit ",[14,52,53],{},"1"," has a lower code point than ",[14,56,57],{},"2",", so ",[14,60,32],{}," sorts before ",[14,63,36],{},". This is technically correct lexicographic behavior, but it contradicts human intuition about numerical ordering.",[10,66,67],{},"Standard sorting functions in most programming languages default to lexicographic order for strings:",[39,69,73],{"className":70,"code":71,"language":72,"meta":47,"style":47},"language-javascript shiki shiki-themes github-light github-dark","const files = ['file1.txt', 'file10.txt', 'file2.txt', 'file20.txt']\nfiles.sort()\n\u002F\u002F Result: ['file1.txt', 'file10.txt', 'file2.txt', 'file20.txt']\n","javascript",[14,74,75,118,131],{"__ignoreMap":47},[76,77,80,84,88,91,95,99,102,105,107,110,112,115],"span",{"class":78,"line":79},"line",1,[76,81,83],{"class":82},"szBVR","const",[76,85,87],{"class":86},"sj4cs"," files",[76,89,90],{"class":82}," =",[76,92,94],{"class":93},"sVt8B"," [",[76,96,98],{"class":97},"sZZnC","'file1.txt'",[76,100,101],{"class":93},", ",[76,103,104],{"class":97},"'file10.txt'",[76,106,101],{"class":93},[76,108,109],{"class":97},"'file2.txt'",[76,111,101],{"class":93},[76,113,114],{"class":97},"'file20.txt'",[76,116,117],{"class":93},"]\n",[76,119,121,124,128],{"class":78,"line":120},2,[76,122,123],{"class":93},"files.",[76,125,127],{"class":126},"sScJk","sort",[76,129,130],{"class":93},"()\n",[76,132,134],{"class":78,"line":133},3,[76,135,137],{"class":136},"sJ8bj","\u002F\u002F Result: ['file1.txt', 'file10.txt', 'file2.txt', 'file20.txt']\n",[23,139,141],{"id":140},"how-natural-sort-works","How Natural Sort Works",[10,143,144],{},"Natural sorting (also called alphanumeric or human sorting) identifies numeric substrings within each string and compares them as integers rather than digit-by-digit. Under natural sort:",[39,146,149],{"className":147,"code":148,"language":44},[42],"file1.txt  →  [\"file\", 1, \".txt\"]\nfile2.txt  →  [\"file\", 2, \".txt\"]\nfile10.txt →  [\"file\", 10, \".txt\"]\nfile20.txt →  [\"file\", 20, \".txt\"]\n",[14,150,148],{"__ignoreMap":47},[10,152,153],{},"Each string is decomposed into alternating text and numeric segments. Text segments compare lexicographically; numeric segments compare by integer value. The result matches human expectations:",[39,155,157],{"className":70,"code":156,"language":72,"meta":47,"style":47},"import { compare } from 'natural-orderby'\n\nconst files = ['file1.txt', 'file10.txt', 'file2.txt', 'file20.txt']\nfiles.sort(compare())\n\u002F\u002F Result: ['file1.txt', 'file2.txt', 'file10.txt', 'file20.txt']\n",[14,158,159,173,179,205,221],{"__ignoreMap":47},[76,160,161,164,167,170],{"class":78,"line":79},[76,162,163],{"class":82},"import",[76,165,166],{"class":93}," { compare } ",[76,168,169],{"class":82},"from",[76,171,172],{"class":97}," 'natural-orderby'\n",[76,174,175],{"class":78,"line":120},[76,176,178],{"emptyLinePlaceholder":177},true,"\n",[76,180,181,183,185,187,189,191,193,195,197,199,201,203],{"class":78,"line":133},[76,182,83],{"class":82},[76,184,87],{"class":86},[76,186,90],{"class":82},[76,188,94],{"class":93},[76,190,98],{"class":97},[76,192,101],{"class":93},[76,194,104],{"class":97},[76,196,101],{"class":93},[76,198,109],{"class":97},[76,200,101],{"class":93},[76,202,114],{"class":97},[76,204,117],{"class":93},[76,206,208,210,212,215,218],{"class":78,"line":207},4,[76,209,123],{"class":93},[76,211,127],{"class":126},[76,213,214],{"class":93},"(",[76,216,217],{"class":126},"compare",[76,219,220],{"class":93},"())\n",[76,222,224],{"class":78,"line":223},5,[76,225,226],{"class":136},"\u002F\u002F Result: ['file1.txt', 'file2.txt', 'file10.txt', 'file20.txt']\n",[23,228,230],{"id":229},"where-this-difference-matters","Where This Difference Matters",[10,232,233,237,238,241,242,245,246,249],{},[234,235,236],"strong",{},"File systems and version lists."," Filenames with numeric suffixes—patches, chapters, logs, screenshots—are the most common case. A directory listing of screenshots sorted alphabetically shows ",[14,239,240],{},"img1.png"," through ",[14,243,244],{},"img9.png",", then ",[14,247,248],{},"img10.png","—unless the viewer uses natural sort.",[10,251,252,255,256,101,259,101,262,265],{},[234,253,254],{},"Part numbers and product codes."," Manufacturing part numbers like ",[14,257,258],{},"A-100",[14,260,261],{},"A-2",[14,263,264],{},"A-10"," should typically sort by the numeric component. Lexicographic order scrambles them.",[10,267,268,271,272,33,275,278],{},[234,269,270],{},"Addresses and room numbers."," Street addresses like ",[14,273,274],{},"221B Baker Street",[14,276,277],{},"10 Downing Street"," sort differently depending on whether the digit sequences are compared as numbers.",[10,280,281,284,285,288,289,292,293,295,296,298],{},[234,282,283],{},"Version strings."," Software versions like ",[14,286,287],{},"v1.10"," vs ",[14,290,291],{},"v1.9"," are a special case. Strict semantic versioning follows its own rules, but a natural sort gets closer than lexicographic order (",[14,294,291],{}," before ",[14,297,287],{},"), while still not matching full semver semantics.",[23,300,302],{"id":301},"implementing-natural-sort","Implementing Natural Sort",[10,304,305],{},"The core algorithm splits each string into tokens of alternating alpha and numeric characters, then compares token-by-token:",[39,307,309],{"className":70,"code":308,"language":72,"meta":47,"style":47},"function naturalCompare(a, b) {\n  const ax = a.split(\u002F(\\d+)\u002F)\n  const bx = b.split(\u002F(\\d+)\u002F)\n\n  for (let i = 0; i \u003C Math.min(ax.length, bx.length); i++) {\n    const an = parseInt(ax[i], 10)\n    const bn = parseInt(bx[i], 10)\n\n    if (isNaN(an) || isNaN(bn)) {\n      \u002F\u002F Text token: compare lexicographically\n      if (ax[i] \u003C bx[i]) return -1\n      if (ax[i] > bx[i]) return 1\n    } else {\n      \u002F\u002F Numeric token: compare as integers\n      if (an \u003C bn) return -1\n      if (an > bn) return 1\n    }\n  }\n\n  return ax.length - bx.length\n}\n\nconst files = ['file1.txt', 'file10.txt', 'file2.txt']\nfiles.sort(naturalCompare)\n\u002F\u002F Result: ['file1.txt', 'file2.txt', 'file10.txt']\n",[14,310,311,333,371,401,405,456,478,497,502,525,531,554,571,583,589,608,623,629,635,640,659,665,670,693,703],{"__ignoreMap":47},[76,312,313,316,319,321,325,327,330],{"class":78,"line":79},[76,314,315],{"class":82},"function",[76,317,318],{"class":126}," naturalCompare",[76,320,214],{"class":93},[76,322,324],{"class":323},"s4XuR","a",[76,326,101],{"class":93},[76,328,329],{"class":323},"b",[76,331,332],{"class":93},") {\n",[76,334,335,338,341,343,346,349,351,354,357,360,363,366,368],{"class":78,"line":120},[76,336,337],{"class":82},"  const",[76,339,340],{"class":86}," ax",[76,342,90],{"class":82},[76,344,345],{"class":93}," a.",[76,347,348],{"class":126},"split",[76,350,214],{"class":93},[76,352,353],{"class":97},"\u002F",[76,355,214],{"class":356},"sA_wV",[76,358,359],{"class":86},"\\d",[76,361,362],{"class":82},"+",[76,364,365],{"class":356},")",[76,367,353],{"class":97},[76,369,370],{"class":93},")\n",[76,372,373,375,378,380,383,385,387,389,391,393,395,397,399],{"class":78,"line":133},[76,374,337],{"class":82},[76,376,377],{"class":86}," bx",[76,379,90],{"class":82},[76,381,382],{"class":93}," b.",[76,384,348],{"class":126},[76,386,214],{"class":93},[76,388,353],{"class":97},[76,390,214],{"class":356},[76,392,359],{"class":86},[76,394,362],{"class":82},[76,396,365],{"class":356},[76,398,353],{"class":97},[76,400,370],{"class":93},[76,402,403],{"class":78,"line":207},[76,404,178],{"emptyLinePlaceholder":177},[76,406,407,410,413,416,419,422,425,428,431,434,437,440,443,446,448,451,454],{"class":78,"line":223},[76,408,409],{"class":82},"  for",[76,411,412],{"class":93}," (",[76,414,415],{"class":82},"let",[76,417,418],{"class":93}," i ",[76,420,421],{"class":82},"=",[76,423,424],{"class":86}," 0",[76,426,427],{"class":93},"; i ",[76,429,430],{"class":82},"\u003C",[76,432,433],{"class":93}," Math.",[76,435,436],{"class":126},"min",[76,438,439],{"class":93},"(ax.",[76,441,442],{"class":86},"length",[76,444,445],{"class":93},", bx.",[76,447,442],{"class":86},[76,449,450],{"class":93},"); i",[76,452,453],{"class":82},"++",[76,455,332],{"class":93},[76,457,459,462,465,467,470,473,476],{"class":78,"line":458},6,[76,460,461],{"class":82},"    const",[76,463,464],{"class":86}," an",[76,466,90],{"class":82},[76,468,469],{"class":126}," parseInt",[76,471,472],{"class":93},"(ax[i], ",[76,474,475],{"class":86},"10",[76,477,370],{"class":93},[76,479,481,483,486,488,490,493,495],{"class":78,"line":480},7,[76,482,461],{"class":82},[76,484,485],{"class":86}," bn",[76,487,90],{"class":82},[76,489,469],{"class":126},[76,491,492],{"class":93},"(bx[i], ",[76,494,475],{"class":86},[76,496,370],{"class":93},[76,498,500],{"class":78,"line":499},8,[76,501,178],{"emptyLinePlaceholder":177},[76,503,505,508,510,513,516,519,522],{"class":78,"line":504},9,[76,506,507],{"class":82},"    if",[76,509,412],{"class":93},[76,511,512],{"class":126},"isNaN",[76,514,515],{"class":93},"(an) ",[76,517,518],{"class":82},"||",[76,520,521],{"class":126}," isNaN",[76,523,524],{"class":93},"(bn)) {\n",[76,526,528],{"class":78,"line":527},10,[76,529,530],{"class":136},"      \u002F\u002F Text token: compare lexicographically\n",[76,532,534,537,540,542,545,548,551],{"class":78,"line":533},11,[76,535,536],{"class":82},"      if",[76,538,539],{"class":93}," (ax[i] ",[76,541,430],{"class":82},[76,543,544],{"class":93}," bx[i]) ",[76,546,547],{"class":82},"return",[76,549,550],{"class":82}," -",[76,552,553],{"class":86},"1\n",[76,555,557,559,561,564,566,568],{"class":78,"line":556},12,[76,558,536],{"class":82},[76,560,539],{"class":93},[76,562,563],{"class":82},">",[76,565,544],{"class":93},[76,567,547],{"class":82},[76,569,570],{"class":86}," 1\n",[76,572,574,577,580],{"class":78,"line":573},13,[76,575,576],{"class":93},"    } ",[76,578,579],{"class":82},"else",[76,581,582],{"class":93}," {\n",[76,584,586],{"class":78,"line":585},14,[76,587,588],{"class":136},"      \u002F\u002F Numeric token: compare as integers\n",[76,590,592,594,597,599,602,604,606],{"class":78,"line":591},15,[76,593,536],{"class":82},[76,595,596],{"class":93}," (an ",[76,598,430],{"class":82},[76,600,601],{"class":93}," bn) ",[76,603,547],{"class":82},[76,605,550],{"class":82},[76,607,553],{"class":86},[76,609,611,613,615,617,619,621],{"class":78,"line":610},16,[76,612,536],{"class":82},[76,614,596],{"class":93},[76,616,563],{"class":82},[76,618,601],{"class":93},[76,620,547],{"class":82},[76,622,570],{"class":86},[76,624,626],{"class":78,"line":625},17,[76,627,628],{"class":93},"    }\n",[76,630,632],{"class":78,"line":631},18,[76,633,634],{"class":93},"  }\n",[76,636,638],{"class":78,"line":637},19,[76,639,178],{"emptyLinePlaceholder":177},[76,641,643,646,649,651,653,656],{"class":78,"line":642},20,[76,644,645],{"class":82},"  return",[76,647,648],{"class":93}," ax.",[76,650,442],{"class":86},[76,652,550],{"class":82},[76,654,655],{"class":93}," bx.",[76,657,658],{"class":86},"length\n",[76,660,662],{"class":78,"line":661},21,[76,663,664],{"class":93},"}\n",[76,666,668],{"class":78,"line":667},22,[76,669,178],{"emptyLinePlaceholder":177},[76,671,673,675,677,679,681,683,685,687,689,691],{"class":78,"line":672},23,[76,674,83],{"class":82},[76,676,87],{"class":86},[76,678,90],{"class":82},[76,680,94],{"class":93},[76,682,98],{"class":97},[76,684,101],{"class":93},[76,686,104],{"class":97},[76,688,101],{"class":93},[76,690,109],{"class":97},[76,692,117],{"class":93},[76,694,696,698,700],{"class":78,"line":695},24,[76,697,123],{"class":93},[76,699,127],{"class":126},[76,701,702],{"class":93},"(naturalCompare)\n",[76,704,706],{"class":78,"line":705},25,[76,707,708],{"class":136},"\u002F\u002F Result: ['file1.txt', 'file2.txt', 'file10.txt']\n",[10,710,711,712,288,715,718,719,33,722,725,726,729],{},"For production use, existing libraries handle edge cases like leading zeros (",[14,713,714],{},"img001",[14,716,717],{},"img1","), decimal numbers, and locale-specific text comparisons. In JavaScript, ",[14,720,721],{},"natural-orderby",[14,723,724],{},"localeCompare"," with the ",[14,727,728],{},"numeric"," option are reliable choices:",[39,731,733],{"className":70,"code":732,"language":72,"meta":47,"style":47},"files.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))\n",[14,734,735],{"__ignoreMap":47},[76,736,737,739,741,744,746,748,750,753,756,758,760,763,766,769,772],{"class":78,"line":79},[76,738,123],{"class":93},[76,740,127],{"class":126},[76,742,743],{"class":93},"((",[76,745,324],{"class":323},[76,747,101],{"class":93},[76,749,329],{"class":323},[76,751,752],{"class":93},") ",[76,754,755],{"class":82},"=>",[76,757,345],{"class":93},[76,759,724],{"class":126},[76,761,762],{"class":93},"(b, ",[76,764,765],{"class":86},"undefined",[76,767,768],{"class":93},", { numeric: ",[76,770,771],{"class":86},"true",[76,773,774],{"class":93}," }))\n",[23,776,778],{"id":777},"leading-zeros","Leading Zeros",[10,780,781,782,33,784,786,787,789],{},"A subtle edge case: strings with leading zeros. Natural sort typically treats ",[14,783,714],{},[14,785,717],{}," as equivalent numerically (both tokenize to ",[14,788,53],{},"), falling back to lexicographic comparison of the digit strings themselves. Some implementations offer options to treat leading zeros as significant for tie-breaking.",[10,791,792,793,797],{},"For quick sorting of any list with natural order, the ",[324,794,796],{"href":795},"\u002Ftools\u002Flist-sorter","List Sorter tool"," supports both lexicographic and natural sort modes out of the box.",[799,800,801],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sA_wV, html code.shiki .sA_wV{--shiki-default:#032F62;--shiki-dark:#DBEDFF}",{"title":47,"searchDepth":120,"depth":120,"links":803},[804,805,806,807,808],{"id":25,"depth":120,"text":26},{"id":140,"depth":120,"text":141},{"id":229,"depth":120,"text":230},{"id":301,"depth":120,"text":302},{"id":777,"depth":120,"text":778},"2026-05-28","Why file10.txt comes after file9.txt in natural sort but not in alphabetical sort.","md",{},"\u002Fguides\u002Fnatural-sort-vs-lexicographic",{"title":5,"description":810},"guides\u002Fnatural-sort-vs-lexicographic","3OfwdeZHkl3XW8M6Q71LwtDSZ4kaoHwDJR-cWUKLx7k",1780401335448]