reduce
Execute async reduction operations on each element in an array and accumulate results.
Basic Usage
typescript
import { reduce } from 'radash'
const numbers = [1, 2, 3, 4, 5]
const sum = await reduce(numbers, async (acc, num) => {
await new Promise(resolve => setTimeout(resolve, 100))
return acc + num
}, 0)
console.log(sum) // 15
Syntax
typescript
function reduce<T, U>(
array: readonly T[],
fn: (acc: U, item: T, index: number, array: readonly T[]) => Promise<U>,
initial: U
): Promise<U>
Parameters
array
(readonly T[]): The array to processfn
(function): Async reduction functionacc
(U): Accumulated valueitem
(T): Current elementindex
(number): Index of current elementarray
(readonly T[]): Original array
initial
(U): Initial value
Return Value
Returns a Promise that resolves to the final accumulated result.
Examples
Basic Async Reduction
typescript
import { reduce } from 'radash'
const numbers = [1, 2, 3, 4, 5]
const sum = await reduce(numbers, async (acc, num) => {
await new Promise(resolve => setTimeout(resolve, 100))
return acc + num
}, 0)
console.log(sum) // 15
Handle Object Arrays
typescript
import { reduce } from 'radash'
const users = [
{ id: 1, name: 'Alice', age: 25 },
{ id: 2, name: 'Bob', age: 30 },
{ id: 3, name: 'Charlie', age: 35 }
]
const userStats = await reduce(users, async (acc, user) => {
// Simulate async operation
await new Promise(resolve => setTimeout(resolve, 50))
return {
totalAge: acc.totalAge + user.age,
names: [...acc.names, user.name],
count: acc.count + 1
}
}, { totalAge: 0, names: [], count: 0 })
console.log(userStats)
// { totalAge: 90, names: ['Alice', 'Bob', 'Charlie'], count: 3 }
Handle API Call Accumulation
typescript
import { reduce } from 'radash'
const userIds = [1, 2, 3, 4, 5]
const userData = await reduce(userIds, async (acc, userId) => {
const response = await fetch(`/api/users/${userId}`)
const user = await response.json()
return {
users: [...acc.users, user],
totalAge: acc.totalAge + user.age,
averageAge: (acc.totalAge + user.age) / (acc.users.length + 1)
}
}, { users: [], totalAge: 0, averageAge: 0 })
console.log(userData)
Handle File Processing
typescript
import { reduce } from 'radash'
const filePaths = ['./file1.txt', './file2.txt', './file3.txt']
const fileStats = await reduce(filePaths, async (acc, filePath) => {
const fs = await import('fs/promises')
const content = await fs.readFile(filePath, 'utf-8')
return {
totalSize: acc.totalSize + content.length,
fileCount: acc.fileCount + 1,
averageSize: (acc.totalSize + content.length) / (acc.fileCount + 1),
files: [...acc.files, { path: filePath, size: content.length }]
}
}, { totalSize: 0, fileCount: 0, averageSize: 0, files: [] })
console.log(fileStats)
Handle Database Queries
typescript
import { reduce } from 'radash'
const categories = ['electronics', 'books', 'clothing']
const categoryStats = await reduce(categories, async (acc, category) => {
const response = await fetch(`/api/products?category=${category}`)
const products = await response.json()
const categoryTotal = products.reduce((sum: number, product: any) =>
sum + product.price, 0
)
return {
totalRevenue: acc.totalRevenue + categoryTotal,
categoryCounts: {
...acc.categoryCounts,
[category]: products.length
},
averagePrice: (acc.totalRevenue + categoryTotal) /
(Object.values(acc.categoryCounts).reduce((a: number, b: number) => a + b, 0) + products.length)
}
}, { totalRevenue: 0, categoryCounts: {}, averagePrice: 0 })
console.log(categoryStats)
Handle Complex Aggregation
typescript
import { reduce } from 'radash'
interface Order {
id: number
customerId: number
amount: number
date: string
}
const orders: Order[] = [
{ id: 1, customerId: 1, amount: 100, date: '2023-01-01' },
{ id: 2, customerId: 1, amount: 200, date: '2023-01-02' },
{ id: 3, customerId: 2, amount: 150, date: '2023-01-01' },
{ id: 4, customerId: 2, amount: 300, date: '2023-01-03' }
]
const orderAnalytics = await reduce(orders, async (acc, order) => {
// Simulate async processing
await new Promise(resolve => setTimeout(resolve, 10))
const customerId = order.customerId
const existingCustomer = acc.customers.find(c => c.id === customerId)
if (existingCustomer) {
existingCustomer.totalSpent += order.amount
existingCustomer.orderCount += 1
} else {
acc.customers.push({
id: customerId,
totalSpent: order.amount,
orderCount: 1
})
}
return {
...acc,
totalRevenue: acc.totalRevenue + order.amount,
totalOrders: acc.totalOrders + 1
}
}, { customers: [], totalRevenue: 0, totalOrders: 0 })
console.log(orderAnalytics)
Handle Error Recovery
typescript
import { reduce } from 'radash'
const urls = [
'https://api.example.com/data1',
'https://api.example.com/data2',
'https://api.example.com/data3'
]
const results = await reduce(urls, async (acc, url) => {
try {
const response = await fetch(url)
if (!response.ok) {
throw new Error(`HTTP ${response.status}`)
}
const data = await response.json()
return {
successful: [...acc.successful, data],
failed: acc.failed,
totalProcessed: acc.totalProcessed + 1
}
} catch (error) {
return {
successful: acc.successful,
failed: [...acc.failed, { url, error: error.message }],
totalProcessed: acc.totalProcessed + 1
}
}
}, { successful: [], failed: [], totalProcessed: 0 })
console.log(results)
Handle Conditional Accumulation
typescript
import { reduce } from 'radash'
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const numberStats = await reduce(numbers, async (acc, num) => {
// Simulate async validation
await new Promise(resolve => setTimeout(resolve, 10))
if (num % 2 === 0) {
return {
...acc,
evenSum: acc.evenSum + num,
evenCount: acc.evenCount + 1
}
} else {
return {
...acc,
oddSum: acc.oddSum + num,
oddCount: acc.oddCount + 1
}
}
}, { evenSum: 0, evenCount: 0, oddSum: 0, oddCount: 0 })
console.log(numberStats)
// { evenSum: 30, evenCount: 5, oddSum: 25, oddCount: 5 }
Handle State Management
typescript
import { reduce } from 'radash'
interface Action {
type: string
payload?: any
}
const actions: Action[] = [
{ type: 'ADD_USER', payload: { id: 1, name: 'Alice' } },
{ type: 'ADD_USER', payload: { id: 2, name: 'Bob' } },
{ type: 'REMOVE_USER', payload: { id: 1 } },
{ type: 'UPDATE_USER', payload: { id: 2, name: 'Bob Updated' } }
]
const finalState = await reduce(actions, async (state, action) => {
// Simulate async state processing
await new Promise(resolve => setTimeout(resolve, 10))
switch (action.type) {
case 'ADD_USER':
return {
...state,
users: [...state.users, action.payload]
}
case 'REMOVE_USER':
return {
...state,
users: state.users.filter(user => user.id !== action.payload.id)
}
case 'UPDATE_USER':
return {
...state,
users: state.users.map(user =>
user.id === action.payload.id
? { ...user, ...action.payload }
: user
)
}
default:
return state
}
}, { users: [] })
console.log(finalState)
Handle Batch Processing
typescript
import { reduce } from 'radash'
const items = Array.from({ length: 100 }, (_, i) => i + 1)
const batchResults = await reduce(items, async (acc, item) => {
// Process in batches of 10
const batch = [...acc.currentBatch, item]
if (batch.length === 10 || item === items[items.length - 1]) {
// Process batch
const batchSum = batch.reduce((sum, num) => sum + num, 0)
return {
processedBatches: [...acc.processedBatches, batchSum],
currentBatch: [],
totalProcessed: acc.totalProcessed + batch.length
}
}
return {
...acc,
currentBatch: batch
}
}, { processedBatches: [], currentBatch: [], totalProcessed: 0 })
console.log(batchResults)
Notes
- Sequential execution: Operations are executed sequentially, not in parallel
- Error handling: If any operation fails, the entire reduce operation fails
- Performance: Suitable for operations that depend on previous results
- Memory: Only stores the accumulated result, not all intermediate results
- Order: Operations are executed in the order of the input array
Differences from Other Functions
Array.prototype.reduce()
: Synchronous operations, doesn't support asyncreduce()
: radash's async reduction methodmap()
: Processes all elements independently, while reduce accumulates
Practical Application Scenarios
- Data aggregation: Accumulate data from multiple sources
- State management: Build complex state from actions
- File processing: Accumulate file statistics
- API processing: Build complex objects from API responses
- Batch operations: Process items in batches with accumulation