ℹ️ Select 'Choose Exercise', or randomize 'Next Random Exercise' in selected language.

Choose Exercise:
Timer 00:00
WPM --
Score --
Acc --
Correct chars --

HTML Table Row Sorter

HTML

Goal -- WPM

Ready
Exercise Algorithm Area
1function sortTableByColumn(tableId, columnIndex, isNumeric = false) {
2const table = document.getElementById(tableId);
3if (!table) {
4console.error(`Table with ID '${tableId}' not found.`);
5return;
6}
7
8const tbody = table.querySelector('tbody');
9if (!tbody) {
10console.error(`Table with ID '${tableId}' has no tbody.`);
11return;
12}
13
14const rows = Array.from(tbody.querySelectorAll('tr'));
15if (rows.length === 0) {
16console.warn(`Table with ID '${tableId}' has no rows to sort.`);
17return;
18}
19
20// Determine sort direction (default ascending)
21let sortDirection = 'asc';
22// A simple way to toggle direction if the function is called multiple times
23// For a real UI, you'd track this state more robustly (e.g., data attributes)
24const currentSortAttribute = table.getAttribute('data-sort-direction');
25if (currentSortAttribute === 'asc') {
26sortDirection = 'desc';
27}
28table.setAttribute('data-sort-direction', sortDirection);
29
30// Get the header cell for the current column to potentially add/remove classes
31const headers = Array.from(table.querySelectorAll('th'));
32if (columnIndex < 0 || columnIndex >= headers.length) {
33console.error(`Invalid columnIndex ${columnIndex} for table with ${headers.length} columns.`);
34return;
35}
36
37// Remove sorting classes from other headers
38headers.forEach((header, index) => {
39if (index !== columnIndex) {
40header.classList.remove('sort-asc', 'sort-desc');
41}
42});
43
44// Add sorting class to the current header
45const currentHeader = headers[columnIndex];
46currentHeader.classList.add(sortDirection === 'asc' ? 'sort-asc' : 'sort-desc');
47
48// Sort the rows
49rows.sort((rowA, rowB) => {
50const cellA = rowA.querySelectorAll('td')[columnIndex];
51const cellB = rowB.querySelectorAll('td')[columnIndex];
52
53let valueA = cellA ? cellA.textContent.trim() : '';
54let valueB = cellB ? cellB.textContent.trim() : '';
55
56// Handle empty cells: treat them as smaller than any non-empty value
57if (valueA === '' && valueB === '') return 0;
58if (valueA === '') return sortDirection === 'asc' ? -1 : 1;
59if (valueB === '') return sortDirection === 'asc' ? 1 : -1;
60
61let comparison = 0;
62if (isNumeric) {
63const numA = parseFloat(valueA);
64const numB = parseFloat(valueB);
65// Handle non-numeric values gracefully if isNumeric is true
66if (isNaN(numA) && isNaN(numB)) comparison = 0;
67else if (isNaN(numA)) comparison = sortDirection === 'asc' ? -1 : 1;
68else if (isNaN(numB)) comparison = sortDirection === 'asc' ? 1 : -1;
69else comparison = numA - numB;
70} else {
71comparison = valueA.localeCompare(valueB);
72}
73
74return sortDirection === 'asc' ? comparison : -comparison;
75});
76
77// Re-append sorted rows to tbody
78rows.forEach(row => tbody.appendChild(row));
79}
80
81// Example of how this might be used with event listeners:
82/*
83const tableHeaders = document.querySelectorAll('#myTable th');
84tableHeaders.forEach((header, index) => {
85header.addEventListener('click', () => {
86// Assuming the first column is numeric, others are strings
87const isNumericColumn = index === 0;
88sortTableByColumn('myTable', index, isNumericColumn);
89});
90});
91*/
Algorithm description viewbox

HTML Table Row Sorter

Algorithm description:

This JavaScript function sorts the rows of an HTML table based on the content of a specified column. It dynamically rearranges the table rows in ascending or descending order, which is a common feature in data-rich web interfaces. A practical use case is displaying a list of products, where users can click on column headers like 'Price' or 'Name' to sort the entire list accordingly.

Algorithm explanation:

The `sortTableByColumn` function takes the ID of the table, the index of the column to sort by, and an optional boolean `isNumeric` to indicate if the column contains numbers. It first retrieves the table and its body, then converts all `<tr>` elements into an array for sorting. The sort direction ('asc' or 'desc') is toggled based on a `data-sort-direction` attribute on the table, providing a simple way to cycle through sorting states. It also updates CSS classes on the table headers to visually indicate the current sort order. The core sorting logic uses `Array.prototype.sort` with a custom comparison function. This function extracts the text content from the cells in the specified column for two rows being compared. It handles empty cells by treating them as the smallest values. If `isNumeric` is true, it attempts to parse cell content as floats, with fallback for non-numeric values. Otherwise, it uses `localeCompare` for string comparison. The final comparison result is multiplied by -1 if the sort direction is descending. After sorting, the rows are re-appended to the `tbody` in their new order. The time complexity is dominated by the sort operation, which is O(N log N) where N is the number of rows, plus O(N*M) for DOM manipulation where M is the number of columns. Space complexity is O(N) for storing the array of rows.

Pseudocode:

FUNCTION sortTableByColumn(tableId, columnIndex, isNumeric):
  GET table element by tableId
  IF table not found THEN
    LOG error and RETURN
  END IF

  GET tbody element from table
  IF tbody not found THEN
    LOG error and RETURN
  END IF

  GET all tr elements from tbody and convert to array 'rows'
  IF rows is empty THEN
    LOG warning and RETURN
  END IF

  DETERMINE sortDirection ('asc' or 'desc') based on table's data-sort-direction attribute, then update attribute

  GET all th elements from table
  IF columnIndex is out of bounds THEN
    LOG error and RETURN
  END IF

  REMOVE sort classes from all headers except the current one
  ADD appropriate sort class ('sort-asc' or 'sort-desc') to the header at columnIndex

  SORT rows array using a custom comparison function:
    GET cellA and cellB at columnIndex for rowA and rowB
    EXTRACT textContent from cellA and cellB, trim whitespace to get valueA and valueB

    HANDLE empty cells: if both empty, return 0; if one empty, return -1 or 1 based on sortDirection

    IF isNumeric THEN
      PARSE valueA and valueB as numbers (numA, numB)
      IF both are NaN, comparison = 0
      ELSE IF numA is NaN, comparison = -1 or 1 based on sortDirection
      ELSE IF numB is NaN, comparison = 1 or -1 based on sortDirection
      ELSE comparison = numA - numB
      END IF
    ELSE
      comparison = valueA.localeCompare(valueB)
    END IF

    RETURN comparison multiplied by -1 if sortDirection is 'desc', otherwise return comparison
  END SORT

  FOR EACH row IN sorted rows:
    APPEND row to tbody
  END FOR
END FUNCTION