forEachReverse
Executes a callback function for each element in an array in reverse order with early termination support.
Iterates through the array from the last element to the first, executing the provided
callback function for each element. If the callback returns false, the iteration
stops immediately. This is useful for operations that need to process elements in
reverse order or when searching backwards through an array.
Signature
const forEachReverse: <Type>(array: Type[], callback: (item: Type, index: number, array: Type[]) => boolean | void) => void
Parameters
| Name | Type | Description |
|---|---|---|
array | - | Array to iterate over in reverse |
callback | - | Callback function to execute for each element |
Examples
Basic reverse iteration
import { forEachReverse } from '@winglet/common-utils';
const numbers = [1, 2, 3, 4, 5];
forEachReverse(numbers, (num, index) => {
console.log(`Index ${index}: ${num}`);
});
// Output: Index 4: 5, Index 3: 4, Index 2: 3, Index 1: 2, Index 0: 1
Early termination while searching backwards
const logs = [
'INFO: Application started',
'DEBUG: Loading config',
'ERROR: Database connection failed',
'INFO: Retrying connection',
'INFO: Connection successful'
];
let lastError: string | undefined;
forEachReverse(logs, (log, index) => {
console.log(`Checking log at index ${index}: ${log}`);
if (log.startsWith('ERROR:')) {
lastError = log;
console.log('Found last error, stopping search');
return false; // Stop iteration
}
});
console.log('Last error:', lastError);
// Output: Checking log at index 4: INFO: Connection successful
// Checking log at index 3: INFO: Retrying connection
// Checking log at index 2: ERROR: Database connection failed
// Found last error, stopping search
// Last error: ERROR: Database connection failed
Reverse processing of user actions
interface Action {
id: number;
type: 'CREATE' | 'UPDATE' | 'DELETE';
timestamp: Date;
data: any;
}
const actions: Action[] = [
{ id: 1, type: 'CREATE', timestamp: new Date('2024-01-01T10:00:00Z'), data: { name: 'Item1' } },
{ id: 2, type: 'UPDATE', timestamp: new Date('2024-01-01T11:00:00Z'), data: { name: 'Item1 Updated' } },
{ id: 3, type: 'DELETE', timestamp: new Date('2024-01-01T12:00:00Z'), data: { id: 1 } }
];
// Process actions in reverse chronological order (undo operations)
forEachReverse(actions, (action, index) => {
console.log(`Undoing action ${action.id}: ${action.type} at ${action.timestamp.toISOString()}`);
// Stop undoing if we reach a CREATE action
if (action.type === 'CREATE') {
console.log('Reached initial CREATE action, stopping undo');
return false;
}
});
Finding the last valid item
interface Product {
id: number;
name: string;
price: number;
isValid: boolean;
}
const products: Product[] = [
{ id: 1, name: 'Laptop', price: 999, isValid: true },
{ id: 2, name: 'Phone', price: -100, isValid: false }, // Invalid price
{ id: 3, name: 'Tablet', price: 399, isValid: true },
{ id: 4, name: 'Watch', price: 0, isValid: false } // Invalid price
];
let lastValidProduct: Product | undefined;
forEachReverse(products, (product, index, array) => {
if (product.isValid && product.price > 0) {
lastValidProduct = product;
console.log(`Found last valid product at index ${index}: ${product.name}`);
return false; // Stop searching
}
console.log(`Skipping invalid product at index ${index}: ${product.name}`);
});
console.log('Last valid product:', lastValidProduct);
Reverse array traversal with conditions
const scores = [85, 92, 78, 95, 88, 91, 87];
const passingGrade = 90;
let consecutivePassing = 0;
forEachReverse(scores, (score, index) => {
console.log(`Checking score at index ${index}: ${score}`);
if (score >= passingGrade) {
consecutivePassing++;
console.log(`Passing grade found. Consecutive count: ${consecutivePassing}`);
} else {
if (consecutivePassing > 0) {
console.log(`Non-passing grade found. Final consecutive count: ${consecutivePassing}`);
return false; // Stop counting
}
}
});
console.log(`Final consecutive passing scores from end: ${consecutivePassing}`);
Stack-like processing
const operations = ['push(1)', 'push(2)', 'push(3)', 'pop()', 'push(4)', 'pop()'];
const stack: number[] = [];
// Process operations in reverse to simulate undo
forEachReverse(operations, (operation, index) => {
console.log(`Undoing operation ${index}: ${operation}`);
if (operation.startsWith('push')) {
// Undo push by removing the element
const value = parseInt(operation.match(/\d+/)?.[0] || '0');
const removedIndex = stack.indexOf(value);
if (removedIndex !== -1) {
stack.splice(removedIndex, 1);
console.log(`Removed ${value} from stack`);
}
} else if (operation === 'pop()') {
// Undo pop by adding back (this is simplified)
console.log('Would restore popped element');
}
console.log('Current stack:', stack);
});
Playground
import { forEachReverse } from '@winglet/common-utils'; const numbers = [1, 2, 3, 4, 5]; forEachReverse(numbers, (num, index) => { console.log(`Index ${index}: ${num}`); }); // Output: Index 4: 5, Index 3: 4, Index 2: 3, Index 1: 2, Index 0: 1
Notes
Reverse Order: Starts from the last element (index array.length - 1) and
moves backwards to the first element (index 0).
Early Termination: Iteration stops immediately when the callback returns false.
Any other return value (including undefined) continues the iteration.
Callback Parameters: The callback function receives three parameters:
item: The current element being processedindex: The current index (original index in the array)array: The entire source array
Performance: Uses a simple reverse for-loop for optimal performance with minimal overhead. Early termination can provide significant performance benefits when searching large arrays.
Use Cases: Ideal for undo operations, finding the last occurrence of something, processing data in LIFO (Last In, First Out) order, or any scenario where reverse iteration provides logical or performance advantages.