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.
—
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.
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]
"""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]
"""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 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']
"""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']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]})")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 itemfrom 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']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