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

key-generation.mddocs/

Key Generation Functions

Functions for generating reusable sorting key functions that can be used with Python's built-in sorting functions. This approach is more efficient when you need to sort multiple times with the same algorithm, as it pre-computes the sorting logic.

Capabilities

Natural Sort Key Generation

Generate a key function for natural sorting that can be reused with built-in sorting functions.

def natsort_keygen(key=None, alg=ns.DEFAULT):
    """
    Generate a key to sort strings and numbers naturally.
    
    This key is designed for use as the 'key' argument to functions
    such as the sorted() builtin or list.sort().

    Parameters:
    - key: callable, optional - A key function applied before parsing for numbers
    - alg: ns enum, optional - Algorithm control flags (default: ns.DEFAULT)

    Returns:
    Callable - A function suitable for use as a sorting key

    Examples:
    >>> key_func = natsort_keygen()
    >>> sorted(['num10', 'num2', 'num1'], key=key_func)
    ['num1', 'num2', 'num10']
    
    >>> # Custom algorithm with case-insensitive real numbers
    >>> key_func = natsort_keygen(alg=ns.REAL | ns.IGNORECASE)
    >>> data = ['Item-5.2', 'item10.1', 'ITEM2.7']
    >>> sorted(data, key=key_func)
    ['Item-5.2', 'ITEM2.7', 'item10.1']
    """

Default Natural Sort Key

Pre-generated natural sort key function using default settings.

natsort_key: Callable[[Any], Tuple[Any, ...]]
"""
The default natural sorting key.

This is the output of natsort_keygen() with default values.
Equivalent to natsort_keygen() but pre-computed for efficiency.

Examples:
>>> sorted(['num10', 'num2', 'num1'], key=natsort_key)
['num1', 'num2', 'num10']
"""

OS Sort Key Generation

Generate a key function that replicates your operating system's file browser sort order.

def os_sort_keygen(key=None):
    """
    Generate a sorting key to replicate your file browser's sort order.
    
    Creates platform-specific sorting keys that match the behavior of
    file explorers on different operating systems.

    Parameters:
    - key: callable, optional - A key function applied before OS sorting

    Returns:
    Callable - A function suitable for OS-native path sorting

    Notes:
    - On Windows: Uses StrCmpLogicalW API for Explorer-compatible sorting
    - On macOS/Linux: Uses ICU collation if available, otherwise locale-based
    - Results will differ intentionally between platforms
    """

Default OS Sort Key

Pre-generated OS sort key function using default settings.

os_sort_key: Callable[[Any], Tuple[Any, ...]]
"""
The default key to replicate your file browser's sort order.

This is the output of os_sort_keygen() with default values.
Platform-specific implementation for consistent OS behavior.

Examples:
>>> import os
>>> files = os.listdir('.')
>>> sorted(files, key=os_sort_key)  # Matches file browser order
"""

Usage Examples

Performance Benefits with Repeated Sorting

from natsort import natsort_keygen, ns
import time

# Large dataset for performance testing
data = [f'item{i}' for i in range(10000, 0, -1)]  # ['item10000', 'item9999', ...]

# Method 1: Using natsorted (recreates key function each time)
start_time = time.time()
for _ in range(100):
    from natsort import natsorted
    result = natsorted(data)
end_time = time.time()
print(f"natsorted method: {end_time - start_time:.4f} seconds")

# Method 2: Using pre-generated key (more efficient for repeated sorting)
key_func = natsort_keygen()
start_time = time.time()
for _ in range(100):
    result = sorted(data, key=key_func)
end_time = time.time()
print(f"key generation method: {end_time - start_time:.4f} seconds")

In-Place Sorting with Generated Keys

from natsort import natsort_keygen, ns

# Sort a list in-place using a generated key
file_list = ['file10.txt', 'file2.txt', 'file1.txt', 'file20.txt']
print(f"Original: {file_list}")

# Create a key function for natural sorting
nat_key = natsort_keygen()
file_list.sort(key=nat_key)
print(f"Sorted in-place: {file_list}")

# Sort with custom algorithm (case-insensitive, real numbers)
mixed_data = ['Value-5.2', 'value10.1', 'VALUE2.7']
print(f"Original mixed: {mixed_data}")

real_key = natsort_keygen(alg=ns.REAL | ns.IGNORECASE)
mixed_data.sort(key=real_key)
print(f"Sorted mixed: {mixed_data}")

Custom Key Functions with Transform

from natsort import natsort_keygen
from pathlib import Path

# Sort file paths by filename only, ignoring directory structure
paths = [
    '/home/user/documents/file10.txt',
    '/var/log/file2.txt',
    '/tmp/file1.txt',
    '/home/user/file20.txt'
]

# Create a key that extracts filename before natural sorting
filename_key = natsort_keygen(key=lambda x: Path(x).name)

sorted_paths = sorted(paths, key=filename_key)
print("Sorted by filename:")
for path in sorted_paths:
    print(f"  {path}")

# Sort by file extension, then by natural order of filename
def extension_then_name(path):
    p = Path(path)
    return (p.suffix, p.stem)  # Sort by extension first, then stem

ext_key = natsort_keygen(key=extension_then_name)

files = ['document.pdf', 'image10.jpg', 'image2.jpg', 'readme.txt', 'data.pdf']
sorted_by_ext = sorted(files, key=ext_key)
print(f"Sorted by extension then name: {sorted_by_ext}")

OS-Compatible File Sorting

from natsort import os_sort_keygen
import os
from pathlib import Path

# Get current directory files
current_dir = Path('.')
files = [f.name for f in current_dir.iterdir() if f.is_file()]

# Sort using OS-native ordering (matches file browser)
os_key = os_sort_keygen()
os_sorted_files = sorted(files, key=os_key)

print("Files sorted in OS-native order:")
for filename in os_sorted_files[:10]:  # Show first 10
    print(f"  {filename}")

# Compare with regular natural sorting
from natsort import natsort_key
nat_sorted_files = sorted(files, key=natsort_key)

print("\nDifferences between OS and natural sorting:")
for i, (os_file, nat_file) in enumerate(zip(os_sorted_files, nat_sorted_files)):
    if os_file != nat_file:
        print(f"  Position {i}: OS='{os_file}' vs Natural='{nat_file}'")

Advanced Algorithm Combinations

from natsort import natsort_keygen, ns

# Complex data requiring multiple algorithm flags
scientific_data = [
    'Experiment-1.5E+10_ResultA',
    'experiment-2.3e-5_resultB', 
    'EXPERIMENT-1.2E+3_resultC',
    'Experiment-5.0_resultD'
]

# Combine multiple algorithm flags:
# - REAL: handle signed floats and scientific notation
# - IGNORECASE: case-insensitive comparison
# - LOWERCASEFIRST: lowercase items come first
complex_key = natsort_keygen(
    alg=ns.REAL | ns.IGNORECASE | ns.LOWERCASEFIRST
)

sorted_scientific = sorted(scientific_data, key=complex_key)
print("Scientific data sorted with complex algorithm:")
for item in sorted_scientific:
    print(f"  {item}")

# Using path-specific sorting for nested directory structures
paths = [
    'data/experiment1/result10.txt',
    'data/experiment1/result2.txt',
    'data/experiment10/result1.txt',
    'data/experiment2/result1.txt'
]

path_key = natsort_keygen(alg=ns.PATH)
sorted_paths = sorted(paths, key=path_key)
print("\nPaths sorted with PATH algorithm:")
for path in sorted_paths:
    print(f"  {path}")

Reusable Keys for Different Data Types

from natsort import natsort_keygen, ns

# Create different specialized keys for different data types
version_key = natsort_keygen(alg=ns.FLOAT)  # For version strings like "1.2.10"
filename_key = natsort_keygen(alg=ns.PATH | ns.IGNORECASE)  # For filenames
human_key = natsort_keygen(alg=ns.LOCALE | ns.IGNORECASE)  # For human-readable text

# Version strings
versions = ['v1.2.10', 'v1.2.2', 'v1.10.1', 'v2.0.0']
print(f"Versions: {sorted(versions, key=version_key)}")

# Filenames (case-insensitive, path-aware)
filenames = ['README.txt', 'src/main.py', 'src/utils.py', 'tests/test_main.py']
print(f"Files: {sorted(filenames, key=filename_key)}")

# Human text (locale-aware, case-insensitive) 
names = ['Müller', 'müller', 'Anderson', 'Åberg']
print(f"Names: {sorted(names, key=human_key)}")

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