Skip to main content

Command Palette

Search for a command to run...

JavaScript Array Sort Method: The Complete Guide to Sorting Strings and Numbers

Published
6 min read

In this article, we will learn Array sort method.

Understanding the Basics

The sort() method sorts the elements of an array in place and returns the sorted array. Here's the key insight: by default, sort() converts all elements to strings and sorts them lexicographically.

const fruits = ['banana', 'apple', 'cherry', 'date'];
console.log(fruits.sort()); // ['apple', 'banana', 'cherry', 'date']

Syntax

array.sort([compareFunction])
  • Without compareFunction: Sorts as strings

  • With compareFunction: Uses custom logic to determine order

How Sort Works for Strings

When sorting strings, JavaScript uses lexicographic order (dictionary order) based on UTF-16 code units.

Basic String Sorting

const names = ['John', 'Alice', 'Bob', 'Charlie'];
names.sort();
console.log(names); // ['Alice', 'Bob', 'Charlie', 'John']

Case Sensitivity in String Sorting

Here's where it gets interesting:

const mixed = ['apple', 'Banana', 'cherry', 'Date'];
mixed.sort();
console.log(mixed); // ['Banana', 'Date', 'apple', 'cherry']

Why? Capital letters have lower UTF-16 values than lowercase letters:

  • 'A' = 65, 'B' = 66, 'C' = 67...

  • 'a' = 97, 'b' = 98, 'c' = 99...

Case-Insensitive String Sorting

const mixed = ['apple', 'Banana', 'cherry', 'Date'];

// Case-insensitive sort
mixed.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
console.log(mixed); // ['apple', 'Banana', 'cherry', 'Date']

Locale-Aware String Sorting

For international applications, use localeCompare():

const words = ['café', 'resume', 'naïve', 'jalapeño'];
words.sort((a, b) => a.localeCompare(b));
console.log(words); // Properly sorted considering accents

The Number Sorting Problem

Here's the classic JavaScript gotcha:

const numbers = [10, 2, 30, 4, 1];
console.log(numbers.sort()); // [1, 10, 2, 30, 4] - NOT what we want!

Why This Happens

JavaScript converts numbers to strings before sorting:

  • 10 becomes "10"

  • 2 becomes "2"

  • 30 becomes "30"

  • 4 becomes "4"

Then it sorts alphabetically:

  • "1" comes before "2"

  • "10" comes before "2" (because "1" < "2")

  • "30" comes before "4" (because "3" < "4")

The Solution: Compare Functions

const numbers = [10, 2, 30, 4, 1];

// Ascending order (smallest to largest)
numbers.sort((a, b) => a - b);
console.log(numbers); // [1, 2, 4, 10, 30]

// Descending order (largest to smallest)
numbers.sort((a, b) => b - a);
console.log(numbers); // [30, 10, 4, 2, 1]

Compare Functions Explained

The compare function is the heart of custom sorting. It takes two arguments and returns:

  • Negative value (< 0): First argument comes before second

  • Zero (0): Elements are equal

  • Positive value (> 0): First argument comes after second

How a - b Works for Numbers

Let's trace through the logic:

const numbers = [5, 2, 8];

// When comparing 5 and 2:
// a = 5, b = 2
// a - b = 5 - 2 = 3 (positive)
// Since 3 > 0, 'a' (5) comes after 'b' (2)

// When comparing 2 and 8:
// a = 2, b = 8
// a - b = 2 - 8 = -6 (negative)
// Since -6 < 0, 'a' (2) comes before 'b' (8)

// Result: [2, 5, 8]

Visual Example with Logging

const numbers = [4, 2, 7, 1];

numbers.sort((a, b) => {
  const result = a - b;
  console.log(`Comparing ${a} and ${b}: ${a} - ${b} = ${result}`);
  console.log(`Decision: ${result < 0 ? `${a} before ${b}` : result > 0 ? `${a} after ${b}` : 'equal'}`);
  return result;
});

// This will show you exactly how the sorting decisions are made

Advanced Sorting Techniques

Sorting Objects by Property

const students = [
  { name: 'Alice', grade: 85, age: 20 },
  { name: 'Bob', grade: 92, age: 19 },
  { name: 'Charlie', grade: 78, age: 21 }
];

// Sort by grade (ascending)
students.sort((a, b) => a.grade - b.grade);

// Sort by name (alphabetically)
students.sort((a, b) => a.name.localeCompare(b.name));

// Sort by age (descending)
students.sort((a, b) => b.age - a.age);

Multi-Level Sorting

const employees = [
  { department: 'IT', name: 'John', salary: 70000 },
  { department: 'HR', name: 'Jane', salary: 65000 },
  { department: 'IT', name: 'Bob', salary: 75000 },
  { department: 'HR', name: 'Alice', salary: 60000 }
];

// Sort by department first, then by salary (descending)
employees.sort((a, b) => {
  // Primary sort: department
  if (a.department !== b.department) {
    return a.department.localeCompare(b.department);
  }
  // Secondary sort: salary (if departments are equal)
  return b.salary - a.salary;
});

console.log(employees);
// HR employees first (Alice, Jane), then IT employees (Bob, John)
// Within each department, sorted by salary (highest first)

Sorting by String Length

const words = ['elephant', 'cat', 'dog', 'butterfly', 'ant'];

// Sort by length (shortest first)
words.sort((a, b) => a.length - b.length);
console.log(words); // ['cat', 'dog', 'ant', 'elephant', 'butterfly']

// Sort by length (longest first)
words.sort((a, b) => b.length - a.length);
console.log(words); // ['butterfly', 'elephant', 'cat', 'dog', 'ant']

Custom Sorting Logic

const tasks = [
  { name: 'Task A', priority: 'high', completed: false },
  { name: 'Task B', priority: 'low', completed: true },
  { name: 'Task C', priority: 'medium', completed: false },
  { name: 'Task D', priority: 'high', completed: true }
];

// Sort by completion status first, then by priority
tasks.sort((a, b) => {
  // Incomplete tasks first
  if (a.completed !== b.completed) {
    return a.completed ? 1 : -1;
  }

  // Then by priority (high > medium > low)
  const priorityOrder = { 'high': 3, 'medium': 2, 'low': 1 };
  return priorityOrder[b.priority] - priorityOrder[a.priority];
});

Performance Considerations

Understanding Sort Complexity

JavaScript's sort typically uses Timsort (a hybrid stable sorting algorithm):

  • Time complexity: O(n log n) average case

  • Space complexity: O(n)

  • Stable sort: Equal elements maintain their relative order

Memory Considerations

// sort() modifies the original array
const original = [3, 1, 4, 1, 5];
const sorted = original.sort((a, b) => a - b);

console.log(original); // [1, 1, 3, 4, 5] - original is modified!
console.log(sorted === original); // true - same reference

// To keep original unchanged
const original = [3, 1, 4, 1, 5];
const sorted = [...original].sort((a, b) => a - b);
// or
const sorted = original.slice().sort((a, b) => a - b);

Real-World Examples

E-commerce Product Sorting

const products = [
  { name: 'Laptop', price: 999.99, rating: 4.5, category: 'Electronics' },
  { name: 'Phone', price: 699.99, rating: 4.8, category: 'Electronics' },
  { name: 'Book', price: 19.99, rating: 4.2, category: 'Education' },
  { name: 'Headphones', price: 199.99, rating: 4.6, category: 'Electronics' }
];

// Sort by price (low to high)
products.sort((a, b) => a.price - b.price);

// Sort by rating (high to low)
products.sort((a, b) => b.rating - a.rating);

// Sort by category, then by price within category
products.sort((a, b) => {
  if (a.category !== b.category) {
    return a.category.localeCompare(b.category);
  }
  return a.price - b.price;
});

Date Sorting

const events = [
  { name: 'Meeting', date: new Date('2024-01-15') },
  { name: 'Conference', date: new Date('2024-01-10') },
  { name: 'Workshop', date: new Date('2024-01-20') }
];

// Sort by date (earliest first)
events.sort((a, b) => a.date - b.date);

// Sort by date (latest first)
events.sort((a, b) => b.date - a.date);

Key Takeaways

  1. Default behavior: sort() converts elements to strings and sorts lexicographically

  2. For numbers: Always use a compare function (a, b) => a - b

  3. For strings: Consider case sensitivity and locale with localeCompare()

  4. Compare function: Return negative, zero, or positive values to control order

  5. In-place sorting: sort() modifies the original array

  6. Stable sort: Equal elements maintain their relative order

  7. Performance: O(n log n) time complexity, minimize work in compare function