How to Sort Text Alphabetically
Sorting a list of names, URLs, keywords, or log lines by hand is tedious and error-prone. Whether you need a quick alphabetical sort or a complex multi-key numeric sort, understanding how sorting works — and which tool to use — saves significant time.
What "Alphabetical Order" Actually Means
Alphabetical (lexicographic) order compares characters one by one using their code point values. In ASCII/Unicode:
- digits
0–9come before uppercaseA–Z - uppercase
A–Zcomes before lowercasea–z - spaces and punctuation have their own positions
This means a naive sort produces results that can surprise you:
Input: Naive sort (ASCII):
banana Apple
Apple banana
cherry cherry
Apple sorts before banana because uppercase A (code point 65) is less than lowercase b (98).
Sort Modes You Need to Know
| Mode | What it does | Example use case |
|---|---|---|
| Ascending A→Z | Standard alphabetical | Alphabetize a word list |
| Descending Z→A | Reverse alphabetical | Prioritize Z entries first |
| Case-insensitive | Ignores upper/lower | Mixed-case name lists |
| Numeric | Sorts by embedded numbers | Log files, version numbers |
| By length | Shortest to longest | Keyword research, CSS |
| Reverse lines | Flips the order | View log files bottom-up |
| Remove duplicates | Unique lines only | Dedup email lists |
Case Sensitivity: The Most Common Trap
When you sort case-insensitively, apple, Apple, and APPLE are treated as equal. The stable sort keeps their original relative order.
Case-sensitive (default ASCII):
Apple
banana
cherry
Case-insensitive (natural):
Apple
banana
cherry
Same result here — but with a list like ["zoo", "Apple", "ant"]:
Case-sensitive: Case-insensitive:
Apple ant
ant Apple
zoo zoo
For most human-facing lists, case-insensitive sort is what you want.
Numeric Sort vs Lexicographic Sort
Sorting version numbers or file names lexicographically gives wrong results:
Lexicographic: Numeric:
v10.0 v1.0
v1.0 v2.0
v2.0 v10.0
The number 10 sorts before 2 lexicographically because the character 1 < 2. Always use numeric sort when your lines contain numbers you care about ordering.
Algorithm: How Sorting Works
Most sort implementations use one of these algorithms:
| Algorithm | Time complexity | Best for |
|---|---|---|
| Timsort (Python, Java) | O(n log n) | Real-world mixed data |
| Introsort (C++, Go) | O(n log n) | General purpose |
| Radix sort | O(n·k) | Fixed-length strings |
| Merge sort | O(n log n) | Stable, linked lists |
For text sorting at any practical scale, the built-in sort of your language is sufficient — they are all O(n log n).
Code Examples
JavaScript
const lines = ["banana", "Apple", "cherry", "ant"];
// Case-insensitive ascending
const sorted = [...lines].sort((a, b) =>
a.localeCompare(b, undefined, { sensitivity: "base" })
);
// ["ant", "Apple", "banana", "cherry"]
// Case-sensitive descending
const descending = [...lines].sort((a, b) => b.localeCompare(a));
// Numeric sort (for lines with numbers)
const versions = ["v10.0", "v2.0", "v1.0"];
const numericSorted = [...versions].sort((a, b) =>
a.localeCompare(b, undefined, { numeric: true })
);
// ["v1.0", "v2.0", "v10.0"]
// Remove duplicates then sort
const unique = [...new Set(lines)].sort((a, b) =>
a.localeCompare(b, undefined, { sensitivity: "base" })
);
Python
lines = ["banana", "Apple", "cherry", "ant"]
# Case-insensitive ascending
sorted_lines = sorted(lines, key=str.lower)
# ['ant', 'Apple', 'banana', 'cherry']
# Descending
sorted_desc = sorted(lines, key=str.lower, reverse=True)
# Numeric sort (natural sort with natsort library)
# pip install natsort
from natsort import natsorted
versions = ["v10.0", "v2.0", "v1.0"]
print(natsorted(versions)) # ['v1.0', 'v2.0', 'v10.0']
# Remove duplicates then sort
unique_sorted = sorted(set(lines), key=str.lower)
# Sort by line length
by_length = sorted(lines, key=len)
Go
package main
import (
"sort"
"strings"
"fmt"
)
func main() {
lines := []string{"banana", "Apple", "cherry", "ant"}
// Case-insensitive ascending
sort.Slice(lines, func(i, j int) bool {
return strings.ToLower(lines[i]) < strings.ToLower(lines[j])
})
fmt.Println(lines) // [ant Apple banana cherry]
// Descending (reverse after sort)
sort.Slice(lines, func(i, j int) bool {
return strings.ToLower(lines[i]) > strings.ToLower(lines[j])
})
// Remove duplicates
seen := make(map[string]bool)
unique := lines[:0]
for _, v := range lines {
key := strings.ToLower(v)
if !seen[key] {
seen[key] = true
unique = append(unique, v)
}
}
}
PHP
<?php
$lines = ["banana", "Apple", "cherry", "ant"];
// Case-insensitive ascending
usort($lines, 'strcasecmp');
print_r($lines); // [ant, Apple, banana, cherry]
// Descending
usort($lines, fn($a, $b) => strcasecmp($b, $a));
// Natural/numeric sort
$versions = ["v10.0", "v2.0", "v1.0"];
natsort($versions);
print_r($versions); // [v1.0, v2.0, v10.0]
// Remove duplicates then sort
$unique = array_unique($lines);
usort($unique, 'strcasecmp');
// Sort by length
usort($lines, fn($a, $b) => strlen($a) - strlen($b));
?>
Locale-Aware Sorting
Different languages have different alphabetical rules:
- In Swedish,
äsorts afterz - In Spanish,
llwas historically a single letter - In German,
üsorts nearuor afterzdepending on context
JavaScript's localeCompare with a locale code handles this:
const names = ["Ångström", "Zebra", "Äpfel"];
// English sort (Ä → A)
names.sort((a, b) => a.localeCompare(b, "en"));
// ["Äpfel", "Ångström", "Zebra"]
// Swedish sort (Ä → after Z)
names.sort((a, b) => a.localeCompare(b, "sv"));
// ["Ångström", "Zebra", "Äpfel"]
For most English content, localeCompare(b, undefined, { sensitivity: "base" }) is the right default.
Quick Reference
| Task | JavaScript | Python | Go | PHP |
|---|---|---|---|---|
| A→Z case-insensitive | localeCompare + sensitivity:"base" |
sorted(key=str.lower) |
strings.ToLower compare |
usort + strcasecmp |
| Z→A | localeCompare reversed |
reverse=True |
> instead of < |
strcasecmp($b,$a) |
| Numeric order | localeCompare + numeric:true |
natsort |
regex extract int | natsort() |
| By length | a.length - b.length |
key=len |
len(a) < len(b) |
strlen($a)-strlen($b) |
| Remove duplicates | new Set() |
set() |
map dedup | array_unique() |
Frequently Asked Questions
Does sorting modify the original array?
In JavaScript, Array.prototype.sort() mutates in place — use [...arr].sort() to get a new array. In Python, sorted() returns a new list while .sort() mutates. In Go, sort.Slice mutates the slice.
How do I sort a CSV column alphabetically?
Parse the CSV into rows, extract the column, sort the rows by that column's value, then re-serialize. Python's csv module with sorted(reader, key=lambda row: row[column_index].lower()) is the most concise approach.
What is "stable sort"?
A stable sort preserves the original relative order of equal elements. Python's sorted(), JavaScript's Array.sort() (since ES2019), and Java's Arrays.sort for objects are all stable. Go's sort.Slice is not stable — use sort.SliceStable if you need it.
How do I sort lines in a text file on the command line?
On Linux/macOS: sort file.txt (add -f for case-insensitive, -n for numeric, -r for reverse, -u for unique). On Windows PowerShell: Get-Content file.txt | Sort-Object.
What's the fastest way to sort a million lines?
Use sort on Linux — it's implemented in C, uses external merge sort for large files, and can handle files larger than RAM with -T /tmp. For in-memory work, Python's Timsort is highly optimized for real-world data.
Why does my sort put numbers before letters?
ASCII/Unicode assigns digits (48–57) lower values than letters (65–122), so 1line sorts before apple by default. Use a case-insensitive locale-aware sort or strip leading digits before comparing if that's not what you want.