CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-natsort

Simple yet flexible natural sorting in Python that enables developers to sort strings containing numbers in a natural, human-expected order rather than lexicographical order.

Pending
Overview
Eval results
Files

index-sorting.mddocs/

Index-Based Sorting

Functions that return sorted indexes rather than sorted sequences, enabling you to sort multiple related sequences by the sort order of one sequence. This is useful when you have related data stored in separate lists that need to be sorted together.

Capabilities

Natural Index Sorting

Returns the list of indexes that would sort the input sequence naturally.

def index_natsorted(seq, key=None, reverse=False, alg=ns.DEFAULT):
    """
    Determine the list of indexes used to sort the input sequence.
    
    Sorts a sequence naturally, but returns a list of the sorted indexes
    instead of the sorted list itself.

    Parameters:
    - seq: iterable - The input to sort
    - key: callable, optional - A key function to determine sorting
    - reverse: bool, optional - Return in reversed order (default: False)
    - alg: ns enum, optional - Algorithm control flags (default: ns.DEFAULT)

    Returns:
    List[int] - The ordered indexes of the input

    Examples:
    >>> index_natsorted(['num3', 'num5', 'num2'])
    [2, 0, 1]
    """

Human-Friendly Index Sorting

Returns indexes for locale-aware sorting order.

def index_humansorted(seq, key=None, reverse=False, alg=ns.DEFAULT):
    """
    This is a wrapper around index_natsorted(seq, alg=ns.LOCALE).

    Parameters:
    - seq: iterable - The input to sort
    - key: callable, optional - A key function to determine sorting
    - reverse: bool, optional - Return in reversed order (default: False)
    - alg: ns enum, optional - Additional algorithm flags (default: ns.DEFAULT)

    Returns:
    List[int] - The ordered indexes of the input using locale-aware sorting

    Examples:
    >>> index_humansorted(['Apple', 'Banana', 'apple', 'banana'])
    [2, 0, 3, 1]
    """

Real Number Index Sorting

Returns indexes for signed float sorting order.

def index_realsorted(seq, key=None, reverse=False, alg=ns.DEFAULT):
    """
    This is a wrapper around index_natsorted(seq, alg=ns.REAL).

    Parameters:
    - seq: iterable - The input to sort
    - key: callable, optional - A key function to determine sorting
    - reverse: bool, optional - Return in reversed order (default: False)
    - alg: ns enum, optional - Additional algorithm flags (default: ns.DEFAULT)

    Returns:
    List[int] - The ordered indexes with proper signed float handling

    Examples:
    >>> index_realsorted(['num5.10', 'num-3', 'num5.3', 'num2'])
    [1, 3, 0, 2]
    """

Order by Index

Order a given sequence by an index sequence, typically used with the output from index_* functions.

def order_by_index(seq, index, iter=False):
    """
    Order a given sequence by an index sequence.
    
    Apply the ordering specified by an index list to reorder a sequence.

    Parameters:
    - seq: sequence - The sequence to order
    - index: iterable - The iterable indicating how to order seq (integers only)
    - iter: bool, optional - Return as iterator if True, list if False (default: False)

    Returns:
    List or Iterator - The sequence ordered by index

    Examples:
    >>> order_by_index(['a', 'b', 'c'], [2, 0, 1])
    ['c', 'a', 'b']
    """

Usage Examples

Sorting Multiple Related Lists

from natsort import index_natsorted, order_by_index

# Multiple related data lists
names = ['item10', 'item2', 'item1', 'item20']
prices = [29.99, 15.50, 9.99, 45.00]
categories = ['electronics', 'books', 'toys', 'electronics']

# Get the natural sort order indexes for names
sort_index = index_natsorted(names)
print(f"Sort indexes: {sort_index}")  # [2, 1, 0, 3]

# Apply the same ordering to all related lists
sorted_names = order_by_index(names, sort_index)
sorted_prices = order_by_index(prices, sort_index)
sorted_categories = order_by_index(categories, sort_index)

print(f"Names: {sorted_names}")        # ['item1', 'item2', 'item10', 'item20']
print(f"Prices: {sorted_prices}")      # [9.99, 15.50, 29.99, 45.00]
print(f"Categories: {sorted_categories}")  # ['toys', 'books', 'electronics', 'electronics']

Working with Complex Data Structures

from natsort import index_natsorted, order_by_index

# Data stored in separate lists (simulating database columns)
ids = ['user10', 'user2', 'user1', 'user20']
names = ['Alice Johnson', 'Bob Smith', 'Charlie Brown', 'Diana Wilson']
scores = [85, 92, 78, 96]
timestamps = ['2023-01-15', '2023-01-10', '2023-01-05', '2023-01-20']

# Sort all data by natural order of user IDs
user_order = index_natsorted(ids)

# Apply consistent ordering across all data
ordered_data = {
    'ids': order_by_index(ids, user_order),
    'names': order_by_index(names, user_order),
    'scores': order_by_index(scores, user_order),
    'timestamps': order_by_index(timestamps, user_order)
}

print("Ordered by user ID:")
for i in range(len(ids)):
    print(f"{ordered_data['ids'][i]}: {ordered_data['names'][i]} "
          f"(Score: {ordered_data['scores'][i]}, Date: {ordered_data['timestamps'][i]})")

Performance with Iterator Option

from natsort import order_by_index

large_data = list(range(1000000))  # Large dataset
sort_indexes = [999999, 0, 500000, 1, 999998]  # Some specific ordering

# Get results as iterator for memory efficiency
ordered_iter = order_by_index(large_data, sort_indexes, iter=True)

# Process results one at a time
for item in ordered_iter:
    print(f"Processing: {item}")
    # Process without loading entire result into memory
    break  # Just showing first item

Reverse Sorting and Custom Keys

from natsort import index_natsorted, order_by_index

# Sorting file paths by filename (ignoring directory)
file_paths = [
    '/home/user/file10.txt',
    '/home/user/file2.txt', 
    '/home/user/file1.txt',
    '/home/user/file20.txt'
]

# Get indexes for reverse natural sort by filename only
indexes = index_natsorted(
    file_paths, 
    key=lambda x: x.split('/')[-1],  # Extract filename
    reverse=True
)

# Apply the ordering
sorted_paths = order_by_index(file_paths, indexes)
print(sorted_paths)
# Output: ['/home/user/file20.txt', '/home/user/file10.txt', 
#          '/home/user/file2.txt', '/home/user/file1.txt']

Working with Real Numbers

from natsort import index_realsorted, order_by_index

# Scientific data with positive and negative values
measurements = ['temp-5.2C', 'temp10.1C', 'temp-12.5C', 'temp2.7C']
locations = ['Station A', 'Station B', 'Station C', 'Station D']
timestamps = ['10:00', '10:15', '10:30', '10:45']

# Sort by temperature value (handling negative numbers)
temp_order = index_realsorted(measurements)

print("Sorted by temperature (coldest first):")
ordered_measurements = order_by_index(measurements, temp_order)
ordered_locations = order_by_index(locations, temp_order)
ordered_timestamps = order_by_index(timestamps, temp_order)

for i in range(len(measurements)):
    print(f"{ordered_measurements[i]} at {ordered_locations[i]} ({ordered_timestamps[i]})")
# Output: temp-12.5C at Station C (10:30)
#         temp-5.2C at Station A (10:00)
#         temp2.7C at Station D (10:45)
#         temp10.1C at Station B (10:15)

Install with Tessl CLI

npx tessl i tessl/pypi-natsort

docs

algorithm-configuration.md

core-sorting.md

index-sorting.md

index.md

key-generation.md

utilities.md

tile.json