diff --git a/docs/api/average.md b/docs/api/average.md index 2a6fc48..6cbcc73 100644 --- a/docs/api/average.md +++ b/docs/api/average.md @@ -191,6 +191,78 @@ items.average('price') // 15 // items.average('invalid') ``` +## Common Use Cases + +### 1. Statistical Analysis + +- Computing averages +- Calculating means +- Processing measurements +- Analyzing datasets + +### 2. Performance Metrics + +- Average response times +- Mean performance scores +- Metric calculations +- KPI analysis + +### 3. Financial Calculations + +- Average transaction value +- Mean account balance +- Spending patterns +- Cost analysis + +### 4. Quality Control + +- Average measurements +- Mean deviations +- Quality metrics +- Process control + +### 5. Sensor Data + +- Average readings +- Mean values +- Sensor metrics +- Data aggregation + +### 6. Academic Scoring + +- Grade averaging +- Score calculations +- Performance metrics +- Assessment analysis + +### 7. Load Balancing + +- Average load +- Mean utilization +- Resource usage +- Capacity planning + +### 8. Time Analysis + +- Average duration +- Mean processing time +- Time metrics +- Period analysis + +### 9. Usage Statistics + +- Average consumption +- Mean usage +- Utilization metrics +- Resource analysis + +### 10. Market Analysis + +- Average prices +- Mean values +- Market metrics +- Trend analysis + ## Return Value Returns a number representing the average value. If the collection is empty or if the specified key doesn't exist, returns 0. diff --git a/docs/api/avg.md b/docs/api/avg.md index a88a4d8..10227be 100644 --- a/docs/api/avg.md +++ b/docs/api/avg.md @@ -1,15 +1,15 @@ # Avg Method -The `avg()` method is an alias of `average()`. It returns the average value of a given key in the collection. If no key is provided, it calculates the average of all elements (assuming they are numbers). +The `avg()` method (alias for `average()`) returns the average of all items in the collection. When given a key, it returns the average of the values of that key across all objects in the collection. ## Basic Syntax ```typescript -// For arrays of numbers -collect(numbers).avg() +// Average of array values +collect(items).avg(): number -// For arrays of objects -collect(items).avg(key) +// Average of object property values +collect(items).avg(key: keyof T): number ``` ## Examples @@ -17,176 +17,310 @@ collect(items).avg(key) ### Basic Usage ```typescript -import { collect } from 'ts-collect' +import { collect } from '@stacksjs/ts-collect' -const numbers = collect([1, 2, 3, 4, 5]) -console.log(numbers.avg()) // 3 -``` - -### With Object Arrays +// Simple array average +const numbers = collect([2, 4, 6, 8, 10]) +console.log(numbers.avg()) // 6 -```typescript -const products = collect([ - { name: 'Keyboard', price: 99 }, - { name: 'Mouse', price: 59 }, - { name: 'Monitor', price: 299 } +// Average with objects +const scores = collect([ + { value: 85 }, + { value: 90 }, + { value: 95 } ]) - -console.log(products.avg('price')) // 152.33 +console.log(scores.avg('value')) // 90 ``` -### Working with Scores +### Working with Objects ```typescript -interface Score { +interface StudentGrade { + studentId: number subject: string - value: number + score: number weight: number } -const scores = collect([ - { subject: 'Math', value: 95, weight: 2 }, - { subject: 'Science', value: 88, weight: 1.5 }, - { subject: 'English', value: 92, weight: 1 } +const grades = collect([ + { studentId: 1, subject: 'Math', score: 85, weight: 1.0 }, + { studentId: 1, subject: 'Science', score: 92, weight: 1.2 }, + { studentId: 1, subject: 'History', score: 78, weight: 0.8 } ]) -const avgScore = scores.avg('value') -console.log(avgScore) // 91.67 +// Simple average +const averageScore = grades.avg('score') // 85 + +// Weighted average +const weightedAvg = grades + .map(grade => grade.score * grade.weight) + .sum() / grades.sum('weight') ``` -### Real-world Example: E-commerce +### Real-world Examples + +#### Performance Metrics ```typescript -interface OrderItem { - productId: number - quantity: number - unitPrice: number - discount: number +interface Performance { + employeeId: string + metric: string + value: number + period: string } -const orderItems = collect([ - { productId: 1, quantity: 2, unitPrice: 29.99, discount: 0 }, - { productId: 2, quantity: 1, unitPrice: 49.99, discount: 5 }, - { productId: 3, quantity: 3, unitPrice: 19.99, discount: 2 } -]) +class PerformanceAnalyzer { + private metrics: Collection -// Average unit price -const avgPrice = orderItems.avg('unitPrice') -console.log(avgPrice) // 33.32 + constructor(metrics: Performance[]) { + this.metrics = collect(metrics) + } -// Average quantity per item -const avgQuantity = orderItems.avg('quantity') -console.log(avgQuantity) // 2 + getAverageMetric(metric: string, period?: string): number { + let filtered = this.metrics.filter(m => m.metric === metric) + if (period) { + filtered = filtered.filter(m => m.period === period) + } + return filtered.avg('value') + } -// Average discount -const avgDiscount = orderItems.avg('discount') -console.log(avgDiscount) // 2.33 + getEmployeeAverage(employeeId: string): number { + return this.metrics + .filter(m => m.employeeId === employeeId) + .avg('value') + } +} ``` -### Working with Performance Metrics +#### Quality Control ```typescript -interface Performance { - day: string - metrics: { - responseTime: number - errorRate: number - userSatisfaction: number - } +interface ProductMeasurement { + batchId: string + timestamp: Date + measurement: number + tolerance: number } -const performanceData = collect([ - { - day: 'Monday', - metrics: { - responseTime: 150, - errorRate: 0.5, - userSatisfaction: 4.2 - } - }, - { - day: 'Tuesday', - metrics: { - responseTime: 145, - errorRate: 0.3, - userSatisfaction: 4.5 - } - }, - { - day: 'Wednesday', - metrics: { - responseTime: 160, - errorRate: 0.4, - userSatisfaction: 4.3 - } +class QualityController { + private measurements: Collection + + constructor(measurements: ProductMeasurement[]) { + this.measurements = collect(measurements) + } + + getBatchAverage(batchId: string): number { + return this.measurements + .filter(m => m.batchId === batchId) + .avg('measurement') + } + + getDeviationFromTarget(target: number): number { + return Math.abs( + target - this.measurements.avg('measurement') + ) } -]) -// Using map and avg together -const avgResponseTime = performanceData - .map(data => data.metrics.responseTime) - .avg() + isWithinTolerance(target: number): boolean { + const avgDeviation = this.measurements + .map(m => Math.abs(m.measurement - target)) + .avg() -console.log(avgResponseTime) // 151.67 + return avgDeviation <= this.measurements.avg('tolerance') + } +} ``` -### Empty Collections +### Advanced Usage + +#### Financial Analysis ```typescript -const empty = collect([]) -console.log(empty.avg()) // 0 +interface Transaction { + date: Date + amount: number + category: string + isRecurring: boolean +} + +class SpendingAnalyzer { + private transactions: Collection + + constructor(transactions: Transaction[]) { + this.transactions = collect(transactions) + } + + getAverageTransaction(): number { + return this.transactions.avg('amount') + } + + getAverageByCategory(category: string): number { + return this.transactions + .filter(t => t.category === category) + .avg('amount') + } -const emptyObjects = collect<{ value: number }>([]) -console.log(emptyObjects.avg('value')) // 0 + getRecurringAverage(): number { + return this.transactions + .filter(t => t.isRecurring) + .avg('amount') + } + + getMonthlyAverage(month: number, year: number): number { + return this.transactions + .filter((t) => { + const date = new Date(t.date) + return date.getMonth() === month + && date.getFullYear() === year + }) + .avg('amount') + } +} ``` -### Chaining with Other Methods +#### Sensor Data Analysis ```typescript -const data = collect([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) +interface SensorReading { + sensorId: string + value: number + confidence: number + timestamp: Date +} + +class SensorAnalyzer { + private readings: Collection -// Average of even numbers -const avgEven = data - .filter(n => n % 2 === 0) - .avg() + constructor(readings: SensorReading[]) { + this.readings = collect(readings) + } -console.log(avgEven) // 6 + getWeightedAverage(sensorId: string): number { + const sensorData = this.readings + .filter(r => r.sensorId === sensorId) -// Average of numbers greater than 5 -const avgGreaterThanFive = data - .filter(n => n > 5) - .avg() + const weightedSum = sensorData + .map(r => r.value * r.confidence) + .sum() + + return weightedSum / sensorData.sum('confidence') + } -console.log(avgGreaterThanFive) // 7.5 + getHourlyAverage(hour: number): number { + return this.readings + .filter(r => r.timestamp.getHours() === hour) + .avg('value') + } + + getConfidenceThresholdAverage(threshold: number): number { + return this.readings + .filter(r => r.confidence >= threshold) + .avg('value') + } +} ``` ## Type Safety -The `avg()` method maintains type safety and will only accept valid keys from your object type: - ```typescript -interface MetricData { +interface TypedItem { + id: number value: number - importance: number + optional?: number } -const metrics = collect([ - { value: 100, importance: 3 }, - { value: 200, importance: 2 }, - { value: 300, importance: 1 } +const items = collect([ + { id: 1, value: 100 }, + { id: 2, value: 200, optional: 50 }, + { id: 3, value: 300 } ]) -// These are valid -const avgValue = metrics.avg('value') // 200 -const avgImportance = metrics.avg('importance') // 2 - -// This would cause a TypeScript error -// metrics.avg('invalidKey') +// Type-safe property access +const avgValue = items.avg('value') // ✓ Valid +const avgOptional = items.avg('optional') // ✓ Valid +// items.avg('nonexistent') // ✗ TypeScript error ``` ## Return Value -Returns a number representing the average value. If the collection is empty or if the specified key doesn't exist, returns 0. +- Returns a number representing the average value +- For arrays: computes average of numeric values +- For objects: computes average of specified property values +- Returns 0 for empty collections +- Maintains type safety with TypeScript +- Handles undefined/null values appropriately + +## Common Use Cases + +### 1. Statistical Analysis + +- Computing averages +- Calculating means +- Processing measurements +- Analyzing datasets + +### 2. Performance Metrics + +- Average response times +- Mean performance scores +- Metric calculations +- KPI analysis + +### 3. Financial Calculations + +- Average transaction value +- Mean account balance +- Spending patterns +- Cost analysis + +### 4. Quality Control + +- Average measurements +- Mean deviations +- Quality metrics +- Process control + +### 5. Sensor Data + +- Average readings +- Mean values +- Sensor metrics +- Data aggregation + +### 6. Academic Scoring + +- Grade averaging +- Score calculations +- Performance metrics +- Assessment analysis + +### 7. Load Balancing + +- Average load +- Mean utilization +- Resource usage +- Capacity planning + +### 8. Time Analysis + +- Average duration +- Mean processing time +- Time metrics +- Period analysis + +### 9. Usage Statistics + +- Average consumption +- Mean usage +- Utilization metrics +- Resource analysis + +### 10. Market Analysis + +- Average prices +- Mean values +- Market metrics +- Trend analysis ## Note diff --git a/docs/api/chunk.md b/docs/api/chunk.md index 6d4588d..43e64c9 100644 --- a/docs/api/chunk.md +++ b/docs/api/chunk.md @@ -1,12 +1,11 @@ # Chunk Method -The `chunk()` method breaks the collection into smaller arrays of a specified size. This is particularly useful for batch processing, pagination, or creating grid layouts. +The `chunk()` method breaks the collection into multiple smaller collections of a given size. This is particularly useful for batch processing, pagination, and creating grid layouts. ## Basic Syntax ```typescript -const size = 5 -collect(items).chunk(size) +collect(items).chunk(size: number): Collection ``` ## Examples @@ -14,191 +13,301 @@ collect(items).chunk(size) ### Basic Usage ```typescript -import { collect } from 'ts-collect' +import { collect } from '@stacksjs/ts-collect' -const numbers = collect([1, 2, 3, 4, 5, 6, 7, 8]) -const chunks = numbers.chunk(3) +// Simple array chunking +const numbers = collect([1, 2, 3, 4, 5, 6, 7]) +console.log(numbers.chunk(3).all()) +// [[1, 2, 3], [4, 5, 6], [7]] -console.log(chunks.all()) -// [ -// [1, 2, 3], -// [4, 5, 6], -// [7, 8] -// ] -``` - -### With Objects - -```typescript -const users = collect([ - { id: 1, name: 'John' }, - { id: 2, name: 'Jane' }, - { id: 3, name: 'Bob' }, - { id: 4, name: 'Alice' } -]) - -const chunkedUsers = users.chunk(2) -console.log(chunkedUsers.all()) -// [ -// [ -// { id: 1, name: 'John' }, -// { id: 2, name: 'Jane' } -// ], -// [ -// { id: 3, name: 'Bob' }, -// { id: 4, name: 'Alice' } -// ] -// ] +// Chunking with even size +const items = collect(['a', 'b', 'c', 'd']) +console.log(items.chunk(2).all()) +// [['a', 'b'], ['c', 'd']] ``` -### Grid Layout Example +### Working with Objects ```typescript -interface GridItem { +interface User { id: number - content: string + name: string + email: string } -const gridItems = collect([ - { id: 1, content: 'Item 1' }, - { id: 2, content: 'Item 2' }, - { id: 3, content: 'Item 3' }, - { id: 4, content: 'Item 4' }, - { id: 5, content: 'Item 5' }, - { id: 6, content: 'Item 6' } +const users = collect([ + { id: 1, name: 'John', email: 'john@example.com' }, + { id: 2, name: 'Jane', email: 'jane@example.com' }, + { id: 3, name: 'Bob', email: 'bob@example.com' }, + { id: 4, name: 'Alice', email: 'alice@example.com' } ]) -// Create rows of 3 items each -const grid = gridItems.chunk(3) -console.log(grid.all()) +const userGroups = users.chunk(2) +console.log(userGroups.all()) // [ // [ -// { id: 1, content: 'Item 1' }, -// { id: 2, content: 'Item 2' }, -// { id: 3, content: 'Item 3' } +// { id: 1, name: 'John', email: 'john@example.com' }, +// { id: 2, name: 'Jane', email: 'jane@example.com' } // ], // [ -// { id: 4, content: 'Item 4' }, -// { id: 5, content: 'Item 5' }, -// { id: 6, content: 'Item 6' } +// { id: 3, name: 'Bob', email: 'bob@example.com' }, +// { id: 4, name: 'Alice', email: 'alice@example.com' } // ] // ] ``` -### Batch Processing Example +### Real-world Examples + +#### Batch Processing ```typescript -interface Task { - id: number - status: 'pending' | 'completed' - priority: number +interface EmailTask { + to: string + subject: string + body: string + attachments?: string[] } -const tasks = collect([ - { id: 1, status: 'pending', priority: 1 }, - { id: 2, status: 'pending', priority: 2 }, - { id: 3, status: 'pending', priority: 1 }, - { id: 4, status: 'pending', priority: 3 }, - { id: 5, status: 'pending', priority: 2 } -]) - -// Process tasks in batches of 2 -const batches = tasks.chunk(2) - -// Simulate batch processing -batches.each((batch) => { - console.log('Processing batch:', batch) - // Process each batch here -}) +class EmailBatchProcessor { + private tasks: Collection + private readonly batchSize: number + + constructor(tasks: EmailTask[], batchSize: number = 50) { + this.tasks = collect(tasks) + this.batchSize = batchSize + } + + async processBatches(): Promise { + const batches = this.tasks.chunk(this.batchSize) + + for (const batch of batches.all()) { + await this.sendBatch(batch) + await this.delay(1000) // Rate limiting + } + } + + private async sendBatch(batch: EmailTask[]): Promise { + // Send emails in batch + for (const task of batch) { + await this.sendEmail(task) + } + } + + private async sendEmail(task: EmailTask): Promise { + // Email sending logic + } + + private delay(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)) + } +} ``` -### Pagination Example +#### Grid Layout Generator ```typescript -interface Post { - id: number - title: string +interface GridItem { + id: string content: string + width: number + height: number } -const posts = collect([ - { id: 1, title: 'Post 1', content: 'Content 1' }, - { id: 2, title: 'Post 2', content: 'Content 2' }, - { id: 3, title: 'Post 3', content: 'Content 3' }, - { id: 4, title: 'Post 4', content: 'Content 4' }, - { id: 5, title: 'Post 5', content: 'Content 5' } -]) - -const itemsPerPage = 2 -const pages = posts.chunk(itemsPerPage) - -// Get specific page -const pageNumber = 1 // (0-based index) -const currentPage = pages.get(pageNumber) -console.log('Current page:', currentPage) -// [ -// { id: 3, title: 'Post 3', content: 'Content 3' }, -// { id: 4, title: 'Post 4', content: 'Content 4' } -// ] +class GridLayoutManager { + private items: Collection + private readonly columnsCount: number + + constructor(items: GridItem[], columns: number = 3) { + this.items = collect(items) + this.columnsCount = columns + } + + generateRows(): GridItem[][] { + return this.items.chunk(this.columnsCount).all() + } + + getRowHeights(): number[] { + return this.items + .chunk(this.columnsCount) + .map(row => Math.max(...row.map(item => item.height))) + .all() + } +} ``` -### Working with Uneven Chunks +### Advanced Usage + +#### Data Partitioning ```typescript -const numbers = collect([1, 2, 3, 4, 5]) -const chunks = numbers.chunk(2) +interface DataPartition { + partitionId: string + items: T[] + totalSize: number +} -console.log(chunks.all()) -// [ -// [1, 2], -// [3, 4], -// [5] // Last chunk may be smaller -// ] +class DataPartitioner { + private data: Collection + private readonly partitionSize: number + + constructor(data: T[], partitionSize: number) { + this.data = collect(data) + this.partitionSize = partitionSize + } + + createPartitions(): Collection> { + return this.data + .chunk(this.partitionSize) + .map((chunk, index) => ({ + partitionId: `partition-${index + 1}`, + items: chunk, + totalSize: chunk.length + })) + } +} ``` -### Combining with Other Methods +#### Test Case Runner ```typescript -const numbers = collect([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) +interface TestCase { + name: string + setup: () => Promise + execute: () => Promise + teardown: () => Promise +} -const evenChunks = numbers - .filter(n => n % 2 === 0) // Get even numbers - .chunk(2) // Group in pairs +class ParallelTestRunner { + private tests: Collection + private readonly concurrency: number -console.log(evenChunks.all()) -// [ -// [2, 4], -// [6, 8], -// [10] -// ] + constructor(tests: TestCase[], concurrency: number = 4) { + this.tests = collect(tests) + this.concurrency = concurrency + } + + async runTests(): Promise { + const batches = this.tests.chunk(this.concurrency) + + for (const batch of batches.all()) { + await Promise.all(batch.map(test => this.runTest(test))) + } + } + + private async runTest(test: TestCase): Promise { + await test.setup() + await test.execute() + await test.teardown() + } +} ``` ## Type Safety -The chunk method maintains type safety throughout the operation: - ```typescript -interface User { +interface TypedItem { id: number - name: string + value: string + metadata?: Record } -const users = collect([ - { id: 1, name: 'John' }, - { id: 2, name: 'Jane' } +const items = collect([ + { id: 1, value: 'one' }, + { id: 2, value: 'two' }, + { id: 3, value: 'three' }, + { id: 4, value: 'four' } ]) -// Type is Collection -const chunkedUsers = users.chunk(1) +// Type-safe chunking +const chunks: Collection = items.chunk(2) -// TypeScript will ensure type safety when working with chunks -chunkedUsers.each((chunk) => { - chunk.forEach((user) => { - console.log(user.name) // TypeScript knows 'name' exists +// TypeScript knows each chunk is an array of TypedItem +chunks.each((chunk) => { + chunk.forEach((item) => { + console.log(item.id) // ✓ Valid + console.log(item.value) // ✓ Valid + console.log(item.metadata) // ✓ Valid (optional) }) }) ``` ## Return Value -Returns a new Collection instance containing arrays of the specified chunk size. The last chunk may contain fewer items if the collection cannot be divided evenly. +- Returns a new Collection of arrays +- Each inner array has the specified size (except possibly the last one) +- Last chunk may have fewer items if collection size isn't evenly divisible +- Original collection remains unchanged +- Maintains type safety with TypeScript +- Can be chained with other collection methods + +## Common Use Cases + +### 1. Batch Processing + +- Processing large datasets +- Rate limiting +- API requests +- Bulk operations + +### 2. UI Components + +- Grid layouts +- Pagination +- Gallery views +- Card layouts + +### 3. Data Partitioning + +- Parallel processing +- Data distribution +- Load balancing +- Sharding + +### 4. Memory Management + +- Processing large arrays +- Stream handling +- Resource optimization +- Memory efficiency + +### 5. Task Distribution + +- Worker allocation +- Job scheduling +- Workload distribution +- Queue management + +### 6. Testing + +- Parallel test execution +- Test grouping +- Resource allocation +- Load simulation + +### 7. Data Export + +- File splitting +- Bulk exports +- Report generation +- Data segmentation + +### 8. Content Layout + +- Content organization +- Page layouts +- Section division +- Display grouping + +### 9. Resource Management + +- Load balancing +- Resource allocation +- Capacity planning +- Usage optimization + +### 10. Network Operations + +- Request batching +- Traffic management +- Connection pooling +- Bandwidth optimization diff --git a/docs/api/groupBy.md b/docs/api/groupBy.md new file mode 100644 index 0000000..ae6dab0 --- /dev/null +++ b/docs/api/groupBy.md @@ -0,0 +1,340 @@ +# GroupBy Method + +The `groupBy()` method groups the collection's items by a given key or callback function. It returns a Map where each key contains a collection of items that match that key. + +## Basic Syntax + +```typescript +// Group by property key +collect(items).groupBy(key: keyof T): Map> + +// Group by callback function +collect(items).groupBy(callback: (item: T) => any): Map> +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from '@stacksjs/ts-collect' + +// Group by simple property +const users = collect([ + { role: 'admin', name: 'John' }, + { role: 'user', name: 'Jane' }, + { role: 'admin', name: 'Bob' } +]) + +const byRole = users.groupBy('role') +console.log(byRole.get('admin').all()) +// [ +// { role: 'admin', name: 'John' }, +// { role: 'admin', name: 'Bob' } +// ] + +// Group by callback +const numbers = collect([1, 2, 3, 4, 5, 6]) +const byEvenOdd = numbers.groupBy(num => num % 2 === 0 ? 'even' : 'odd') +``` + +### Working with Objects + +```typescript +interface Transaction { + id: number + amount: number + category: string + date: Date +} + +const transactions = collect([ + { id: 1, amount: 100, category: 'food', date: new Date('2024-01-01') }, + { id: 2, amount: 200, category: 'transport', date: new Date('2024-01-01') }, + { id: 3, amount: 150, category: 'food', date: new Date('2024-01-02') } +]) + +// Group by category +const byCategory = transactions.groupBy('category') + +// Group by date using callback +const byDate = transactions.groupBy(trans => + trans.date.toISOString().split('T')[0] +) +``` + +### Real-world Examples + +#### Order Management + +```typescript +interface Order { + id: string + status: 'pending' | 'processing' | 'completed' | 'cancelled' + total: number + customerId: string + items: string[] +} + +class OrderManager { + private orders: Collection + + constructor(orders: Order[]) { + this.orders = collect(orders) + } + + getOrdersByStatus(): Map> { + return this.orders.groupBy('status') + } + + getOrdersByCustomer(): Map> { + return this.orders.groupBy('customerId') + } + + getOrdersByValueTier(): Map> { + return this.orders.groupBy((order) => { + if (order.total < 100) + return 'small' + if (order.total < 500) + return 'medium' + return 'large' + }) + } +} +``` + +#### Analytics System + +```typescript +interface Event { + timestamp: Date + eventType: string + userId: string + metadata: Record +} + +class AnalyticsProcessor { + private events: Collection + + constructor(events: Event[]) { + this.events = collect(events) + } + + getEventsByType(): Map> { + return this.events.groupBy('eventType') + } + + getEventsByHour(): Map> { + return this.events.groupBy(event => event.timestamp.getHours()) + } + + getEventsByUser(): Map> { + return this.events.groupBy('userId') + } + + getEventsByTimeframe(): Map> { + return this.events.groupBy((event) => { + const hour = event.timestamp.getHours() + if (hour < 6) + return 'night' + if (hour < 12) + return 'morning' + if (hour < 18) + return 'afternoon' + return 'evening' + }) + } +} +``` + +### Advanced Usage + +#### Multi-level Grouping + +```typescript +interface Student { + id: string + grade: number + class: string + subject: string + score: number +} + +class GradeAnalyzer { + private scores: Collection + + constructor(scores: Student[]) { + this.scores = collect(scores) + } + + getScoresByGradeAndClass(): Map>> { + const byGrade = this.scores.groupBy('grade') + + return new Map([...byGrade].map(([grade, students]) => [ + grade, + students.groupBy('class') + ])) + } + + getAveragesBySubject(): Map { + const bySubject = this.scores.groupBy('subject') + return new Map([...bySubject].map(([subject, students]) => [ + subject, + students.avg('score') + ])) + } +} +``` + +#### Dynamic Grouping + +```typescript +type GroupingStrategy = 'status' | 'priority' | 'assignee' | 'custom' + +interface Task { + id: string + title: string + status: string + priority: number + assignee: string + tags: string[] +} + +class TaskOrganizer { + private tasks: Collection + + constructor(tasks: Task[]) { + this.tasks = collect(tasks) + } + + groupTasks(strategy: GroupingStrategy): Map> { + switch (strategy) { + case 'status': + return this.tasks.groupBy('status') + case 'priority': + return this.tasks.groupBy(task => + task.priority <= 1 + ? 'low' + : task.priority <= 3 ? 'medium' : 'high' + ) + case 'assignee': + return this.tasks.groupBy('assignee') + case 'custom': + return this.tasks.groupBy(task => + task.tags.length ? task.tags[0] : 'untagged' + ) + } + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + category: string + value: number + metadata?: Record +} + +const items = collect([ + { id: 1, category: 'A', value: 100 }, + { id: 2, category: 'B', value: 200 }, + { id: 3, category: 'A', value: 300 } +]) + +// Type-safe property grouping +const byCategory = items.groupBy('category') +const byValueRange = items.groupBy(item => item.value > 200 ? 'high' : 'low') + +// Type checking on grouped collections +byCategory.get('A')?.each((item) => { + console.log(item.id) // ✓ Valid + console.log(item.value) // ✓ Valid + console.log(item.metadata) // ✓ Valid (optional) +}) +``` + +## Return Value + +- Returns a Map object where: + - Keys are the grouping values + - Values are Collections containing matching items +- Each sub-collection maintains the original item types +- Original collection remains unchanged +- Maintains type safety with TypeScript +- Can handle undefined/null values +- Can be chained with other collection methods + +## Common Use Cases + +### 1. Data Organization + +- Category grouping +- Status organization +- Type classification +- Data clustering + +### 2. Analysis + +- Data segmentation +- Pattern analysis +- Distribution studies +- Trend identification + +### 3. Reporting + +- Data aggregation +- Summary creation +- Results grouping +- Category analysis + +### 4. User Management + +- Role-based grouping +- Permission management +- User categorization +- Access control + +### 5. Financial Analysis + +- Transaction grouping +- Category analysis +- Expense tracking +- Revenue classification + +### 6. Time-based Analysis + +- Time period grouping +- Event organization +- Schedule management +- Timeline creation + +### 7. Resource Management + +- Resource allocation +- Capacity planning +- Usage tracking +- Asset organization + +### 8. Performance Analysis + +- Metric grouping +- Result classification +- Performance tracking +- Benchmark organization + +### 9. Content Management + +- Content organization +- Category management +- Tag grouping +- Hierarchy creation + +### 10. Inventory Management + +- Product categorization +- Stock organization +- Supply grouping +- Location tracking diff --git a/docs/api/max.md b/docs/api/max.md new file mode 100644 index 0000000..a170455 --- /dev/null +++ b/docs/api/max.md @@ -0,0 +1,309 @@ +# Max Method + +The `max()` method returns the maximum value in the collection. When given a key, it returns the maximum value of that key across all objects in the collection. + +## Basic Syntax + +```typescript +// Max of array values +collect(items).max(): T | undefined + +// Max of object property values +collect(items).max(key: keyof T): T | undefined +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from '@stacksjs/ts-collect' + +// Simple array maximum +const numbers = collect([5, 3, 8, 1, 9]) +console.log(numbers.max()) // 9 + +// Maximum with objects +const scores = collect([ + { value: 85 }, + { value: 92 }, + { value: 78 }, + { value: 95 } +]) +console.log(scores.max('value')) // 95 +``` + +### Working with Objects + +```typescript +interface Product { + id: number + name: string + price: number + stock: number +} + +const products = collect([ + { id: 1, name: 'Laptop', price: 999, stock: 5 }, + { id: 2, name: 'Mouse', price: 25, stock: 15 }, + { id: 3, name: 'Keyboard', price: 59, stock: 8 } +]) + +// Find highest price +const highestPrice = products.max('price') // 999 + +// Find highest stock +const highestStock = products.max('stock') // 15 +``` + +### Real-world Examples + +#### Performance Analysis + +```typescript +interface PerformanceMetric { + timestamp: Date + throughput: number + responseTime: number + errorCount: number +} + +class PerformanceAnalyzer { + private metrics: Collection + + constructor(metrics: PerformanceMetric[]) { + this.metrics = collect(metrics) + } + + getPeakThroughput(): number | undefined { + return this.metrics.max('throughput') + } + + getWorstResponseTime(period: Date): number | undefined { + return this.metrics + .filter(m => m.timestamp >= period) + .max('responseTime') + } + + getHighestErrorRate(): number | undefined { + return this.metrics.max('errorCount') + } +} +``` + +#### Resource Monitoring + +```typescript +interface ResourceUsage { + resourceId: string + cpuUsage: number + memoryUsage: number + timestamp: Date +} + +class ResourceMonitor { + private usage: Collection + + constructor(usage: ResourceUsage[]) { + this.usage = collect(usage) + } + + getPeakCPUUsage(resourceId: string): number | undefined { + return this.usage + .filter(u => u.resourceId === resourceId) + .max('cpuUsage') + } + + getPeakMemoryUsage(): number | undefined { + return this.usage.max('memoryUsage') + } + + getMostStressedResource(): string | undefined { + return this.usage + .sortByDesc('cpuUsage') + .first() + ?.resourceId + } +} +``` + +### Advanced Usage + +#### Sales Analytics + +```typescript +interface SalesRecord { + orderId: string + amount: number + profit: number + customerSegment: string + timestamp: Date +} + +class SalesAnalyzer { + private sales: Collection + + constructor(sales: SalesRecord[]) { + this.sales = collect(sales) + } + + getLargestOrder(): number | undefined { + return this.sales.max('amount') + } + + getHighestProfit(segment?: string): number | undefined { + let query = this.sales + if (segment) { + query = query.filter(s => s.customerSegment === segment) + } + return query.max('profit') + } + + getPeakSalesDay(): Date | undefined { + return this.sales + .sortByDesc('amount') + .first() + ?.timestamp + } +} +``` + +#### Athletic Performance + +```typescript +interface AthletePerformance { + athleteId: string + event: string + score: number + wind: number + altitude: number +} + +class PerformanceTracker { + private performances: Collection + + constructor(performances: AthletePerformance[]) { + this.performances = collect(performances) + } + + getPersonalBest(athleteId: string): number | undefined { + return this.performances + .filter(p => p.athleteId === athleteId) + .max('score') + } + + getEventRecord(event: string, maxWind: number = 2.0): number | undefined { + return this.performances + .filter(p => p.event === event && p.wind <= maxWind) + .max('score') + } + + getHighestAltitudePerformance(): AthletePerformance | undefined { + return this.performances + .sortByDesc('altitude') + .first() + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + value: number + optional?: number +} + +const items = collect([ + { id: 1, value: 100 }, + { id: 2, value: 200, optional: 50 }, + { id: 3, value: 300 } +]) + +// Type-safe property access +const maxValue = items.max('value') // ✓ Valid +const maxOptional = items.max('optional') // ✓ Valid +// items.max('nonexistent') // ✗ TypeScript error +``` + +## Return Value + +- Returns the maximum value in the collection +- Returns undefined for empty collections +- For objects, returns maximum value of specified property +- Maintains type safety with TypeScript +- Handles undefined/null values appropriately +- Compares values using standard JavaScript comparison operators + +## Common Use Cases + +### 1. Performance Analysis + +- Peak performance +- Maximum throughput +- Highest efficiency +- Best results + +### 2. Resource Monitoring + +- Peak usage +- Maximum capacity +- Highest demand +- Resource limits + +### 3. Financial Analysis + +- Highest profits +- Maximum returns +- Peak values +- Top performance + +### 4. Sports Analytics + +- Best performances +- Record scores +- Peak achievements +- Top results + +### 5. Sales Analysis + +- Highest sales +- Peak periods +- Maximum revenue +- Best performers + +### 6. Load Testing + +- Peak loads +- Maximum stress +- Highest demand +- Capacity limits + +### 7. Usage Analytics + +- Peak usage +- Maximum concurrent +- Highest activity +- Top utilization + +### 8. Environmental Monitoring + +- Maximum readings +- Peak levels +- Highest values +- Critical thresholds + +### 9. Quality Control + +- Maximum tolerance +- Highest deviation +- Peak measures +- Upper limits + +### 10. System Monitoring + +- Peak performance +- Maximum load +- Highest activity +- Critical points diff --git a/docs/api/median.md b/docs/api/median.md new file mode 100644 index 0000000..3b90ac2 --- /dev/null +++ b/docs/api/median.md @@ -0,0 +1,310 @@ +# Median Method + +The `median()` method returns the median value of the collection. When given a key, it returns the median of the values of that key across all objects in the collection. + +## Basic Syntax + +```typescript +// Median of array values +collect(items).median(): number | undefined + +// Median of object property values +collect(items).median(key: keyof T): number | undefined +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from '@stacksjs/ts-collect' + +// Simple array median +const numbers = collect([1, 5, 2, 8, 3]) +console.log(numbers.median()) // 3 + +// Median with objects +const scores = collect([ + { value: 85 }, + { value: 90 }, + { value: 95 }, + { value: 82 }, + { value: 88 } +]) +console.log(scores.median('value')) // 88 +``` + +### Working with Objects + +```typescript +interface SalesRecord { + id: number + amount: number + region: string + quarter: number +} + +const sales = collect([ + { id: 1, amount: 1000, region: 'North', quarter: 1 }, + { id: 2, amount: 1500, region: 'South', quarter: 1 }, + { id: 3, amount: 750, region: 'East', quarter: 1 }, + { id: 4, amount: 2000, region: 'West', quarter: 1 }, + { id: 5, amount: 1250, region: 'Central', quarter: 1 } +]) + +// Find median sale amount +const medianAmount = sales.median('amount') // 1250 +``` + +### Real-world Examples + +#### Price Analysis + +```typescript +interface PropertyListing { + id: string + price: number + sqft: number + bedrooms: number + location: string +} + +class PropertyAnalyzer { + private listings: Collection + + constructor(listings: PropertyListing[]) { + this.listings = collect(listings) + } + + getMedianPrice(): number | undefined { + return this.listings.median('price') + } + + getMedianPricePerSqft(): number | undefined { + return this.listings + .map(listing => listing.price / listing.sqft) + .median() + } + + getMedianByBedrooms(bedrooms: number): number | undefined { + return this.listings + .filter(listing => listing.bedrooms === bedrooms) + .median('price') + } +} +``` + +#### Performance Metrics + +```typescript +interface PerformanceMetric { + timestamp: Date + responseTime: number + errorRate: number + throughput: number +} + +class PerformanceAnalyzer { + private metrics: Collection + + constructor(metrics: PerformanceMetric[]) { + this.metrics = collect(metrics) + } + + getMedianResponseTime(): number | undefined { + return this.metrics.median('responseTime') + } + + getMedianErrorRate(): number | undefined { + return this.metrics.median('errorRate') + } + + getHourlyMedian(hour: number): number | undefined { + return this.metrics + .filter(metric => metric.timestamp.getHours() === hour) + .median('responseTime') + } +} +``` + +### Advanced Usage + +#### Statistical Analysis + +```typescript +interface DataPoint { + value: number + confidence: number + category: string + timestamp: Date +} + +class StatisticalAnalyzer { + private data: Collection + + constructor(data: DataPoint[]) { + this.data = collect(data) + } + + getMedianByCategory(category: string): number | undefined { + return this.data + .filter(point => point.category === category) + .median('value') + } + + getConfidenceWeightedMedian(): number | undefined { + return this.data + .map(point => point.value * point.confidence) + .median() + } + + getTimeWindowMedian(startTime: Date, endTime: Date): number | undefined { + return this.data + .filter(point => + point.timestamp >= startTime + && point.timestamp <= endTime + ) + .median('value') + } +} +``` + +#### Student Grade Analysis + +```typescript +interface Grade { + studentId: string + subject: string + score: number + term: string + weight: number +} + +class GradeAnalyzer { + private grades: Collection + + constructor(grades: Grade[]) { + this.grades = collect(grades) + } + + getMedianBySubject(subject: string): number | undefined { + return this.grades + .filter(grade => grade.subject === subject) + .median('score') + } + + getWeightedMedian(): number | undefined { + return this.grades + .map(grade => grade.score * grade.weight) + .median() + } + + getTermMedian(term: string): number | undefined { + return this.grades + .filter(grade => grade.term === term) + .median('score') + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + value: number + optional?: number +} + +const items = collect([ + { id: 1, value: 100 }, + { id: 2, value: 200, optional: 50 }, + { id: 3, value: 300 } +]) + +// Type-safe property access +const medianValue = items.median('value') // ✓ Valid +const medianOptional = items.median('optional') // ✓ Valid +// items.median('nonexistent') // ✗ TypeScript error +``` + +## Return Value + +- Returns the median value of the collection +- Returns undefined for empty collections +- For even number of items, returns average of two middle values +- For objects, returns median of specified property values +- Maintains type safety with TypeScript +- Handles undefined/null values appropriately + +## Common Use Cases + +### 1. Statistical Analysis + +- Finding central tendency +- Analyzing distributions +- Processing datasets +- Outlier detection + +### 2. Price Analysis + +- Market pricing +- Cost analysis +- Value assessment +- Price trends + +### 3. Performance Metrics + +- Response times +- Load analysis +- System metrics +- Resource usage + +### 4. Academic Scoring + +- Grade analysis +- Score distributions +- Performance assessment +- Student evaluation + +### 5. Financial Analysis + +- Transaction values +- Asset pricing +- Market analysis +- Cost assessment + +### 6. Time Series Analysis + +- Duration analysis +- Response patterns +- Time distributions +- Process timing + +### 7. Quality Control + +- Measurement analysis +- Process control +- Deviation assessment +- Quality metrics + +### 8. Load Balancing + +- Resource distribution +- Usage patterns +- Capacity analysis +- Workload assessment + +### 9. Demographic Analysis + +- Population metrics +- Distribution analysis +- Trend assessment +- Pattern recognition + +### 10. Sensor Data + +- Measurement analysis +- Reading distributions +- Signal processing +- Data normalization diff --git a/docs/api/min.md b/docs/api/min.md new file mode 100644 index 0000000..6af6c38 --- /dev/null +++ b/docs/api/min.md @@ -0,0 +1,306 @@ +# Min Method + +The `min()` method returns the minimum value in the collection. When given a key, it returns the minimum value of that key across all objects in the collection. + +## Basic Syntax + +```typescript +// Min of array values +collect(items).min(): T | undefined + +// Min of object property values +collect(items).min(key: keyof T): T | undefined +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from '@stacksjs/ts-collect' + +// Simple array minimum +const numbers = collect([5, 3, 8, 1, 9]) +console.log(numbers.min()) // 1 + +// Minimum with objects +const scores = collect([ + { value: 85 }, + { value: 92 }, + { value: 78 }, + { value: 95 } +]) +console.log(scores.min('value')) // 78 +``` + +### Working with Objects + +```typescript +interface Product { + id: number + name: string + price: number + stock: number +} + +const products = collect([ + { id: 1, name: 'Laptop', price: 999, stock: 5 }, + { id: 2, name: 'Mouse', price: 25, stock: 15 }, + { id: 3, name: 'Keyboard', price: 59, stock: 8 } +]) + +// Find lowest price +const lowestPrice = products.min('price') // 25 + +// Find lowest stock +const lowestStock = products.min('stock') // 5 +``` + +### Real-world Examples + +#### Price Analysis + +```typescript +interface PricePoint { + timestamp: Date + price: number + volume: number + exchange: string +} + +class PriceAnalyzer { + private prices: Collection + + constructor(prices: PricePoint[]) { + this.prices = collect(prices) + } + + getDailyLow(date: Date): number | undefined { + return this.prices + .filter(p => this.isSameDay(p.timestamp, date)) + .min('price') + } + + getLowestVolume(): number | undefined { + return this.prices.min('volume') + } + + private isSameDay(d1: Date, d2: Date): boolean { + return d1.toDateString() === d2.toDateString() + } +} +``` + +#### Performance Metrics + +```typescript +interface Metric { + serviceId: string + responseTime: number + errorRate: number + timestamp: Date +} + +class PerformanceMonitor { + private metrics: Collection + + constructor(metrics: Metric[]) { + this.metrics = collect(metrics) + } + + getBestResponseTime(serviceId?: string): number | undefined { + let query = this.metrics + if (serviceId) { + query = query.filter(m => m.serviceId === serviceId) + } + return query.min('responseTime') + } + + getLowestErrorRate(): number | undefined { + return this.metrics.min('errorRate') + } +} +``` + +### Advanced Usage + +#### Resource Allocation + +```typescript +interface ResourceUsage { + resourceId: string + utilization: number + cost: number + timestamp: Date +} + +class ResourceManager { + private usage: Collection + + constructor(usage: ResourceUsage[]) { + this.usage = collect(usage) + } + + findLeastUtilizedResource(): string | undefined { + return this.usage + .sortBy('utilization') + .first() + ?.resourceId + } + + getLowestCostResource(): string | undefined { + return this.usage + .filter(u => u.utilization < 80) // Only consider available resources + .sortBy('cost') + .first() + ?.resourceId + } + + getMinUtilizationByResource(resourceId: string): number | undefined { + return this.usage + .filter(u => u.resourceId === resourceId) + .min('utilization') + } +} +``` + +#### Temperature Monitoring + +```typescript +interface TemperatureReading { + sensorId: string + temperature: number + humidity: number + timestamp: Date +} + +class TemperatureMonitor { + private readings: Collection + + constructor(readings: TemperatureReading[]) { + this.readings = collect(readings) + } + + getLowestTemperature(sensorId?: string): number | undefined { + let query = this.readings + if (sensorId) { + query = query.filter(r => r.sensorId === sensorId) + } + return query.min('temperature') + } + + getLowestHumidity(): number | undefined { + return this.readings.min('humidity') + } + + getLowestReadingTime(sensorId: string): Date | undefined { + return this.readings + .filter(r => r.sensorId === sensorId) + .sortBy('temperature') + .first() + ?.timestamp + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + value: number + optional?: number +} + +const items = collect([ + { id: 1, value: 100 }, + { id: 2, value: 200, optional: 50 }, + { id: 3, value: 300 } +]) + +// Type-safe property access +const minValue = items.min('value') // ✓ Valid +const minOptional = items.min('optional') // ✓ Valid +// items.min('nonexistent') // ✗ TypeScript error +``` + +## Return Value + +- Returns the minimum value in the collection +- Returns undefined for empty collections +- For objects, returns minimum value of specified property +- Maintains type safety with TypeScript +- Handles undefined/null values appropriately +- Compares values using standard JavaScript comparison operators + +## Common Use Cases + +### 1. Price Analysis + +- Finding lowest prices +- Cost minimization +- Value comparison +- Pricing strategies + +### 2. Performance Metrics + +- Best response times +- Lowest error rates +- Optimal performance +- Resource efficiency + +### 3. Resource Management + +- Minimum utilization +- Lowest costs +- Resource optimization +- Capacity planning + +### 4. Environmental Monitoring + +- Temperature minimums +- Humidity lows +- Sensor readings +- Climate analysis + +### 5. Financial Analysis + +- Lowest values +- Minimum balances +- Risk assessment +- Cost analysis + +### 6. Inventory Management + +- Lowest stock levels +- Minimum quantities +- Order thresholds +- Supply management + +### 7. Load Balancing + +- Minimum load +- Resource availability +- Capacity planning +- Usage optimization + +### 8. Quality Control + +- Minimum tolerances +- Lowest measures +- Quality thresholds +- Process control + +### 9. Time Analysis + +- Shortest durations +- Minimum intervals +- Time optimization +- Process efficiency + +### 10. Score Analysis + +- Lowest scores +- Minimum ratings +- Performance floors +- Baseline measures diff --git a/docs/api/mode.md b/docs/api/mode.md new file mode 100644 index 0000000..bf2b048 --- /dev/null +++ b/docs/api/mode.md @@ -0,0 +1,307 @@ +# Mode Method + +The `mode()` method returns the most frequent value in the collection. When given a key, it returns the most frequent value of that key across all objects in the collection. + +## Basic Syntax + +```typescript +// Mode of array values +collect(items).mode(): T | undefined + +// Mode of object property values +collect(items).mode(key: keyof T): T | undefined +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from '@stacksjs/ts-collect' + +// Simple array mode +const numbers = collect([1, 2, 2, 3, 3, 3, 4]) +console.log(numbers.mode()) // 3 + +// Mode with objects +const ratings = collect([ + { score: 5 }, + { score: 4 }, + { score: 5 }, + { score: 3 }, + { score: 5 } +]) +console.log(ratings.mode('score')) // 5 +``` + +### Working with Objects + +```typescript +interface Product { + id: number + category: string + price: number + rating: number +} + +const products = collect([ + { id: 1, category: 'electronics', price: 100, rating: 4 }, + { id: 2, category: 'books', price: 20, rating: 5 }, + { id: 3, category: 'electronics', price: 150, rating: 4 }, + { id: 4, category: 'clothing', price: 50, rating: 4 } +]) + +// Find most common category +const popularCategory = products.mode('category') // 'electronics' + +// Find most common rating +const commonRating = products.mode('rating') // 4 +``` + +### Real-world Examples + +#### Customer Behavior Analysis + +```typescript +interface Purchase { + customerId: string + productId: string + category: string + amount: number + dayOfWeek: number +} + +class CustomerAnalyzer { + private purchases: Collection + + constructor(purchases: Purchase[]) { + this.purchases = collect(purchases) + } + + getMostPopularCategory(): string | undefined { + return this.purchases.mode('category') + } + + getMostCommonPurchaseDay(): number | undefined { + return this.purchases.mode('dayOfWeek') + } + + getCustomerPreference(customerId: string): string | undefined { + return this.purchases + .filter(p => p.customerId === customerId) + .mode('category') + } +} +``` + +#### Vote Counter + +```typescript +interface Vote { + candidateId: string + precinct: string + timestamp: Date + method: 'in-person' | 'mail' | 'electronic' +} + +class VoteAnalyzer { + private votes: Collection + + constructor(votes: Vote[]) { + this.votes = collect(votes) + } + + getWinningCandidate(): string | undefined { + return this.votes.mode('candidateId') + } + + getMostCommonVotingMethod(): string | undefined { + return this.votes.mode('method') + } + + getPrecinctWinner(precinct: string): string | undefined { + return this.votes + .filter(vote => vote.precinct === precinct) + .mode('candidateId') + } +} +``` + +### Advanced Usage + +#### Inventory Analysis + +```typescript +interface InventoryMovement { + productId: string + location: string + quantity: number + action: 'in' | 'out' + reason: string +} + +class InventoryAnalyzer { + private movements: Collection + + constructor(movements: InventoryMovement[]) { + this.movements = collect(movements) + } + + getMostActiveLocation(): string | undefined { + return this.movements.mode('location') + } + + getMostCommonReason(): string | undefined { + return this.movements + .filter(m => m.action === 'out') + .mode('reason') + } + + getProductMostFrequentLocation(productId: string): string | undefined { + return this.movements + .filter(m => m.productId === productId) + .mode('location') + } +} +``` + +#### Survey Results + +```typescript +interface SurveyResponse { + respondentId: string + question: string + answer: string + demographic: string + timeSpent: number +} + +class SurveyAnalyzer { + private responses: Collection + + constructor(responses: SurveyResponse[]) { + this.responses = collect(responses) + } + + getMostCommonAnswer(question: string): string | undefined { + return this.responses + .filter(r => r.question === question) + .mode('answer') + } + + getDemographicPreference(demographic: string): string | undefined { + return this.responses + .filter(r => r.demographic === demographic) + .mode('answer') + } + + getMostEngagedDemographic(): string | undefined { + return this.responses + .filter(r => r.timeSpent > this.responses.avg('timeSpent')) + .mode('demographic') + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + category: string + value: number + optional?: string +} + +const items = collect([ + { id: 1, category: 'A', value: 100 }, + { id: 2, category: 'B', value: 200 }, + { id: 3, category: 'A', value: 300 } +]) + +// Type-safe property access +const modeCategory = items.mode('category') // ✓ Valid +const modeOptional = items.mode('optional') // ✓ Valid +// items.mode('nonexistent') // ✗ TypeScript error +``` + +## Return Value + +- Returns the most frequent value in the collection +- Returns undefined for empty collections +- If multiple values have the same frequency, returns the first one +- For objects, returns most frequent value of specified property +- Maintains type safety with TypeScript +- Handles undefined/null values appropriately + +## Common Use Cases + +### 1. Statistical Analysis + +- Finding most common values +- Analyzing frequencies +- Pattern detection +- Distribution analysis + +### 2. Customer Behavior + +- Popular choices +- Common preferences +- Buying patterns +- User habits + +### 3. Voting Systems + +- Winner determination +- Preference analysis +- Choice aggregation +- Opinion tracking + +### 4. Inventory Management + +- Popular items +- Common locations +- Movement patterns +- Stock analysis + +### 5. Survey Analysis + +- Common responses +- Popular opinions +- Response patterns +- Demographic trends + +### 6. Error Analysis + +- Common issues +- Frequent problems +- Error patterns +- Issue tracking + +### 7. Performance Monitoring + +- Common states +- Frequent conditions +- Status patterns +- System behavior + +### 8. Usage Analytics + +- Popular features +- Common actions +- User patterns +- Behavior analysis + +### 9. Quality Control + +- Common defects +- Frequent issues +- Pattern detection +- Problem analysis + +### 10. Market Analysis + +- Popular products +- Common prices +- Purchase patterns +- Consumer preferences diff --git a/docs/api/partition.md b/docs/api/partition.md new file mode 100644 index 0000000..5153761 --- /dev/null +++ b/docs/api/partition.md @@ -0,0 +1,328 @@ +# Partition Method + +The `partition()` method separates a collection into two collections based on a predicate function. The first collection contains elements that pass the truth test, while the second contains elements that fail. + +## Basic Syntax + +```typescript +collect(items).partition((item: T) => boolean): [Collection, Collection] +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from '@stacksjs/ts-collect' + +// Partition numbers by even/odd +const numbers = collect([1, 2, 3, 4, 5, 6]) +const [evens, odds] = numbers.partition(num => num % 2 === 0) + +console.log(evens.all()) // [2, 4, 6] +console.log(odds.all()) // [1, 3, 5] + +// Partition strings by length +const words = collect(['cat', 'dog', 'elephant', 'fox', 'butterfly']) +const [short, long] = words.partition(word => word.length <= 3) + +console.log(short.all()) // ['cat', 'dog', 'fox'] +console.log(long.all()) // ['elephant', 'butterfly'] +``` + +### Working with Objects + +```typescript +interface Task { + id: number + title: string + completed: boolean + priority: number +} + +const tasks = collect([ + { id: 1, title: 'Task 1', completed: true, priority: 1 }, + { id: 2, title: 'Task 2', completed: false, priority: 2 }, + { id: 3, title: 'Task 3', completed: true, priority: 3 }, + { id: 4, title: 'Task 4', completed: false, priority: 1 } +]) + +// Partition by completion status +const [completed, pending] = tasks.partition(task => task.completed) + +// Partition by priority +const [highPriority, lowPriority] = tasks.partition(task => task.priority > 1) +``` + +### Real-world Examples + +#### Email Filter + +```typescript +interface Email { + id: string + subject: string + from: string + content: string + spam_score: number + date: Date +} + +class EmailFilter { + private emails: Collection + private spamThreshold: number + + constructor(emails: Email[], spamThreshold: number = 0.7) { + this.emails = collect(emails) + this.spamThreshold = spamThreshold + } + + filterSpam(): [Collection, Collection] { + return this.emails.partition(email => + email.spam_score < this.spamThreshold + ) + } + + getNewEmails(cutoffDate: Date): [Collection, Collection] { + return this.emails.partition(email => + email.date >= cutoffDate + ) + } +} +``` + +#### Quality Control + +```typescript +interface ProductBatch { + batchId: string + measurements: number[] + temperature: number + humidity: number + defectRate: number +} + +class QualityController { + private batches: Collection + private tolerances: { + maxDefectRate: number + tempRange: [number, number] + } + + constructor( + batches: ProductBatch[], + tolerances = { maxDefectRate: 0.05, tempRange: [20, 25] } + ) { + this.batches = collect(batches) + this.tolerances = tolerances + } + + separateByQuality(): [Collection, Collection] { + return this.batches.partition(batch => + this.isWithinSpecifications(batch) + ) + } + + private isWithinSpecifications(batch: ProductBatch): boolean { + return batch.defectRate <= this.tolerances.maxDefectRate + && batch.temperature >= this.tolerances.tempRange[0] + && batch.temperature <= this.tolerances.tempRange[1] + } +} +``` + +### Advanced Usage + +#### Transaction Processor + +```typescript +interface Transaction { + id: string + amount: number + status: 'pending' | 'processed' | 'failed' + riskScore: number + metadata: Record +} + +class TransactionProcessor { + private transactions: Collection + private riskThreshold: number + + constructor(transactions: Transaction[], riskThreshold: number = 0.8) { + this.transactions = collect(transactions) + this.riskThreshold = riskThreshold + } + + separateByRisk(): [Collection, Collection] { + return this.transactions.partition(transaction => + transaction.riskScore < this.riskThreshold + ) + } + + separateByProcessability(): [Collection, Collection] { + return this.transactions.partition((transaction) => { + return transaction.status === 'pending' + && transaction.amount > 0 + && this.hasRequiredMetadata(transaction) + }) + } + + private hasRequiredMetadata(transaction: Transaction): boolean { + const required = ['userId', 'timestamp', 'currency'] + return required.every(field => field in transaction.metadata) + } +} +``` + +#### Student Performance Analysis + +```typescript +interface StudentRecord { + studentId: string + grades: number[] + attendance: number + participation: number + finalExam?: number +} + +class PerformanceAnalyzer { + private records: Collection + + constructor(records: StudentRecord[]) { + this.records = collect(records) + } + + separateByPerformance(): [Collection, Collection] { + return this.records.partition(record => + this.isHighPerforming(record) + ) + } + + separateByRisk(): [Collection, Collection] { + return this.records.partition((record) => { + const avgGrade = this.calculateAverage(record.grades) + return avgGrade >= 70 && record.attendance >= 0.8 + }) + } + + private isHighPerforming(record: StudentRecord): boolean { + const avgGrade = this.calculateAverage(record.grades) + return avgGrade >= 85 + && record.attendance >= 0.9 + && record.participation >= 0.8 + } + + private calculateAverage(grades: number[]): number { + return grades.reduce((sum, grade) => sum + grade, 0) / grades.length + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + value: string + status: 'active' | 'inactive' + metadata?: Record +} + +const items = collect([ + { id: 1, value: 'one', status: 'active' }, + { id: 2, value: 'two', status: 'inactive' }, + { id: 3, value: 'three', status: 'active' } +]) + +// Type-safe partitioning +const [active, inactive] = items.partition(item => item.status === 'active') + +// TypeScript knows both collections have TypedItem elements +active.each((item) => { + console.log(item.id) // ✓ Valid + console.log(item.value) // ✓ Valid + console.log(item.metadata) // ✓ Valid (optional) +}) +``` + +## Return Value + +- Returns a tuple of two collections `[Collection, Collection]` + - First collection contains elements that pass the predicate + - Second collection contains elements that fail the predicate +- Both collections maintain the original item types +- Original collection remains unchanged +- Maintains type safety with TypeScript +- Can be chained with other collection methods + +## Common Use Cases + +### 1. Data Filtering + +- Pass/fail separation +- Valid/invalid division +- Accept/reject sorting +- Include/exclude splitting + +### 2. Quality Control + +- Pass/fail testing +- Compliance checking +- Standard adherence +- Quality assessment + +### 3. Risk Analysis + +- High/low risk separation +- Safety assessment +- Risk management +- Threat evaluation + +### 4. Performance Analysis + +- Above/below threshold +- Pass/fail criteria +- Performance metrics +- Efficiency measures + +### 5. User Management + +- Active/inactive users +- Role-based separation +- Access control +- Permission management + +### 6. Content Moderation + +- Approved/rejected content +- Flagged items +- Content filtering +- Moderation queues + +### 7. Financial Processing + +- Valid/invalid transactions +- Risk assessment +- Fraud detection +- Payment processing + +### 8. Resource Allocation + +- Available/unavailable +- Allocated/unallocated +- Used/unused +- Reserved/free + +### 9. Task Management + +- Complete/incomplete +- Assigned/unassigned +- Priority sorting +- Status separation + +### 10. Error Handling + +- Success/failure separation +- Error categorization +- Exception handling +- Status processing diff --git a/docs/api/sum.md b/docs/api/sum.md new file mode 100644 index 0000000..05fd689 --- /dev/null +++ b/docs/api/sum.md @@ -0,0 +1,301 @@ +# Sum Method + +The `sum()` method returns the sum of all items in the collection. When given a key, it returns the sum of the values of that key across all objects in the collection. + +## Basic Syntax + +```typescript +// Sum of array values +collect(items).sum(): number + +// Sum of object property values +collect(items).sum(key: keyof T): number +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from '@stacksjs/ts-collect' + +// Simple array sum +const numbers = collect([1, 2, 3, 4, 5]) +console.log(numbers.sum()) // 15 + +// Sum with objects +const items = collect([ + { value: 10 }, + { value: 20 }, + { value: 30 } +]) +console.log(items.sum('value')) // 60 +``` + +### Working with Objects + +```typescript +interface Transaction { + id: number + amount: number + tax: number + discount: number +} + +const transactions = collect([ + { id: 1, amount: 100, tax: 10, discount: 5 }, + { id: 2, amount: 200, tax: 20, discount: 10 }, + { id: 3, amount: 300, tax: 30, discount: 15 } +]) + +// Sum individual properties +const totalAmount = transactions.sum('amount') // 600 +const totalTax = transactions.sum('tax') // 60 +const totalDiscount = transactions.sum('discount') // 30 +``` + +### Real-world Examples + +#### Sales Analysis + +```typescript +interface SaleRecord { + orderId: string + items: number + subtotal: number + tax: number + shipping: number +} + +class SalesAnalyzer { + private sales: Collection + + constructor(sales: SaleRecord[]) { + this.sales = collect(sales) + } + + getTotalRevenue(): number { + return this.sales.sum('subtotal') + } + + getTotalTax(): number { + return this.sales.sum('tax') + } + + getGrossTotal(): number { + return this.sales + .map(sale => sale.subtotal + sale.tax + sale.shipping) + .sum() + } +} +``` + +#### Budget Calculator + +```typescript +interface BudgetItem { + category: string + planned: number + actual: number + variance?: number +} + +class BudgetAnalyzer { + private items: Collection + + constructor(items: BudgetItem[]) { + this.items = collect(items) + } + + getTotalPlanned(): number { + return this.items.sum('planned') + } + + getTotalActual(): number { + return this.items.sum('actual') + } + + getVariance(): number { + return this.items + .map(item => item.actual - item.planned) + .sum() + } +} +``` + +### Advanced Usage + +#### Portfolio Analysis + +```typescript +interface Investment { + symbol: string + shares: number + costBasis: number + currentPrice: number +} + +class PortfolioManager { + private investments: Collection + + constructor(investments: Investment[]) { + this.investments = collect(investments) + } + + getTotalCost(): number { + return this.investments + .map(inv => inv.shares * inv.costBasis) + .sum() + } + + getCurrentValue(): number { + return this.investments + .map(inv => inv.shares * inv.currentPrice) + .sum() + } + + getTotalGainLoss(): number { + return this.investments + .map(inv => inv.shares * (inv.currentPrice - inv.costBasis)) + .sum() + } +} +``` + +#### Time Tracking + +```typescript +interface TimeEntry { + taskId: string + duration: number // in minutes + billable: boolean + rate?: number +} + +class TimeTracker { + private entries: Collection + + constructor(entries: TimeEntry[]) { + this.entries = collect(entries) + } + + getTotalTime(): number { + return this.entries.sum('duration') + } + + getBillableTime(): number { + return this.entries + .filter(entry => entry.billable) + .sum('duration') + } + + getBillableAmount(): number { + return this.entries + .filter(entry => entry.billable && entry.rate) + .map(entry => (entry.duration / 60) * (entry.rate || 0)) + .sum() + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + value: number + optional?: number +} + +const items = collect([ + { id: 1, value: 100 }, + { id: 2, value: 200, optional: 50 }, + { id: 3, value: 300 } +]) + +// Type-safe property access +const totalValue = items.sum('value') // ✓ Valid +const totalOptional = items.sum('optional') // ✓ Valid +// items.sum('nonexistent') // ✗ TypeScript error +``` + +## Return Value + +- Returns a number representing the sum +- For arrays: adds all numeric values +- For objects: adds values of specified property +- Non-numeric values are typically ignored +- Returns 0 for empty collections +- Maintains type safety with TypeScript + +## Common Use Cases + +### 1. Financial Calculations + +- Calculating totals +- Summing transactions +- Computing balances +- Adding expenses + +### 2. Quantity Management + +- Inventory totals +- Order quantities +- Stock calculations +- Usage metrics + +### 3. Statistics + +- Data aggregation +- Score totals +- Point calculations +- Metric summation + +### 4. Time Tracking + +- Duration totals +- Billable hours +- Time accumulation +- Period calculations + +### 5. Budget Analysis + +- Expense totals +- Revenue calculations +- Budget variances +- Cost aggregation + +### 6. Performance Metrics + +- Score totals +- Rating calculations +- Performance sums +- Metric aggregation + +### 7. Resource Management + +- Usage totals +- Allocation sums +- Capacity calculations +- Resource totals + +### 8. Analytics + +- Data summation +- Metric totals +- Usage statistics +- Value aggregation + +### 9. Sales Analysis + +- Revenue totals +- Sales aggregation +- Commission calculations +- Discount totals + +### 10. Inventory Management + +- Stock totals +- Order quantities +- Value calculations +- Weight summations diff --git a/docs/api/where.md b/docs/api/where.md new file mode 100644 index 0000000..df36e40 --- /dev/null +++ b/docs/api/where.md @@ -0,0 +1,305 @@ +# Where Method + +The `where()` method filters the collection by a given key-value pair, returning a new collection with all items where the given key matches the given value. + +## Basic Syntax + +```typescript +collect(items).where(key: keyof T, value: T[key]): Collection +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from '@stacksjs/ts-collect' + +// Simple filtering +const users = collect([ + { name: 'John', role: 'admin' }, + { name: 'Jane', role: 'user' }, + { name: 'Bob', role: 'admin' } +]) + +const admins = users.where('role', 'admin') +console.log(admins.all()) +// [ +// { name: 'John', role: 'admin' }, +// { name: 'Bob', role: 'admin' } +// ] +``` + +### Working with Objects + +```typescript +interface Product { + id: number + category: string + price: number + inStock: boolean +} + +const products = collect([ + { id: 1, category: 'electronics', price: 100, inStock: true }, + { id: 2, category: 'books', price: 20, inStock: false }, + { id: 3, category: 'electronics', price: 200, inStock: true } +]) + +// Get all electronics +const electronics = products.where('category', 'electronics') + +// Get in-stock items +const available = products.where('inStock', true) +``` + +### Real-world Examples + +#### Order Management + +```typescript +interface Order { + id: string + status: 'pending' | 'processing' | 'completed' | 'cancelled' + customerId: string + total: number + priority: boolean +} + +class OrderManager { + private orders: Collection + + constructor(orders: Order[]) { + this.orders = collect(orders) + } + + getPendingOrders(): Collection { + return this.orders.where('status', 'pending') + } + + getCustomerOrders(customerId: string): Collection { + return this.orders.where('customerId', customerId) + } + + getPriorityOrders(): Collection { + return this.orders.where('priority', true) + } +} +``` + +#### User Authentication + +```typescript +interface User { + id: string + email: string + status: 'active' | 'suspended' | 'banned' + role: string + verified: boolean +} + +class UserAuthenticator { + private users: Collection + + constructor(users: User[]) { + this.users = collect(users) + } + + findByEmail(email: string): User | undefined { + return this.users.where('email', email).first() + } + + getActiveUsers(): Collection { + return this.users.where('status', 'active') + } + + getVerifiedUsers(): Collection { + return this.users.where('verified', true) + } + + getUsersByRole(role: string): Collection { + return this.users.where('role', role) + } +} +``` + +### Advanced Usage + +#### Inventory System + +```typescript +interface InventoryItem { + sku: string + locationId: string + status: 'available' | 'reserved' | 'shipped' + quantity: number + needsRestock: boolean +} + +class InventoryManager { + private inventory: Collection + + constructor(items: InventoryItem[]) { + this.inventory = collect(items) + } + + getLocationInventory(locationId: string): Collection { + return this.inventory.where('locationId', locationId) + } + + getAvailableItems(): Collection { + return this.inventory.where('status', 'available') + } + + getRestockNeeded(): Collection { + return this.inventory.where('needsRestock', true) + } + + getReservedItems(): Collection { + return this.inventory + .where('status', 'reserved') + .filter(item => item.quantity > 0) + } +} +``` + +#### Permission System + +```typescript +interface Permission { + resourceId: string + roleId: string + access: 'read' | 'write' | 'admin' + enabled: boolean +} + +class PermissionManager { + private permissions: Collection + + constructor(permissions: Permission[]) { + this.permissions = collect(permissions) + } + + getRolePermissions(roleId: string): Collection { + return this.permissions + .where('roleId', roleId) + .where('enabled', true) + } + + getResourceAccess(resourceId: string): Collection { + return this.permissions + .where('resourceId', resourceId) + .where('enabled', true) + } + + getAdminPermissions(): Collection { + return this.permissions.where('access', 'admin') + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + status: 'active' | 'inactive' + category: string + metadata?: Record +} + +const items = collect([ + { id: 1, status: 'active', category: 'A' }, + { id: 2, status: 'inactive', category: 'B' }, + { id: 3, status: 'active', category: 'A' } +]) + +// Type-safe key-value filtering +const activeItems = items.where('status', 'active') +const categoryA = items.where('category', 'A') + +// TypeScript enforces valid keys and values +// items.where('invalid', 'value') // ✗ TypeScript error +// items.where('status', 'invalid') // ✗ TypeScript error +``` + +## Return Value + +- Returns a new Collection containing items matching the key-value pair +- Returns empty collection if no matches found +- Original collection remains unchanged +- Maintains type safety with TypeScript +- Can be chained with other collection methods +- Value comparison uses strict equality (===) + +## Common Use Cases + +### 1. Record Filtering + +- Status filtering +- Category matching +- Type selection +- State filtering + +### 2. User Management + +- Role-based filtering +- Status checking +- Permission validation +- Account management + +### 3. Status Tracking + +- State monitoring +- Progress tracking +- Status filtering +- Condition checking + +### 4. Inventory Control + +- Stock management +- Location filtering +- Status tracking +- Availability checking + +### 5. Order Processing + +- Status filtering +- Priority management +- Category sorting +- Type filtering + +### 6. Access Control + +- Permission checking +- Role validation +- Access management +- Security filtering + +### 7. Data Classification + +- Category filtering +- Type matching +- Group selection +- Class filtering + +### 8. Resource Management + +- Status tracking +- Availability checking +- Type filtering +- State management + +### 9. Event Handling + +- Type filtering +- Status matching +- Category selection +- Priority management + +### 10. Configuration Management + +- State filtering +- Type matching +- Environment selection +- Mode filtering diff --git a/docs/api/whereBetween.md b/docs/api/whereBetween.md new file mode 100644 index 0000000..1f660bc --- /dev/null +++ b/docs/api/whereBetween.md @@ -0,0 +1,297 @@ +# WhereBetween Method + +The `whereBetween()` method filters the collection to get items where the given key's value is between the given minimum and maximum values (inclusive). + +## Basic Syntax + +```typescript +collect(items).whereBetween(key: keyof T, min: T[K], max: T[K]): Collection +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from '@stacksjs/ts-collect' + +// Filter numbers in range +const numbers = collect([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) +const between = numbers.whereBetween('value', 4, 7) +console.log(between.all()) // [4, 5, 6, 7] + +// Filter objects by numeric property +const items = collect([ + { id: 1, score: 50 }, + { id: 2, score: 75 }, + { id: 3, score: 90 }, + { id: 4, score: 60 } +]) + +const midScores = items.whereBetween('score', 60, 80) +``` + +### Working with Objects + +```typescript +interface Product { + id: number + name: string + price: number + stock: number + weight: number +} + +const products = collect([ + { id: 1, name: 'Item 1', price: 100, stock: 5, weight: 1.2 }, + { id: 2, name: 'Item 2', price: 200, stock: 10, weight: 2.5 }, + { id: 3, name: 'Item 3', price: 150, stock: 3, weight: 1.8 }, + { id: 4, name: 'Item 4', price: 300, stock: 8, weight: 3.0 } +]) + +// Filter by price range +const midPriceProducts = products.whereBetween('price', 150, 250) + +// Filter by stock range +const stockRange = products.whereBetween('stock', 5, 10) +``` + +### Real-world Examples + +#### Price Filter + +```typescript +interface PriceRange { + min: number + max: number + label: string +} + +class PriceFilter { + private items: Collection + private ranges: PriceRange[] + + constructor(items: Product[]) { + this.items = collect(items) + this.ranges = [ + { min: 0, max: 100, label: 'Budget' }, + { min: 101, max: 500, label: 'Mid-Range' }, + { min: 501, max: 1000, label: 'Premium' } + ] + } + + getItemsInRange(label: string): Collection { + const range = this.ranges.find(r => r.label === label) + if (!range) + return collect([]) + return this.items.whereBetween('price', range.min, range.max) + } + + getCustomRange(min: number, max: number): Collection { + return this.items.whereBetween('price', min, max) + } +} +``` + +#### Date Range Filter + +```typescript +interface Event { + id: string + title: string + date: Date + attendees: number +} + +class EventManager { + private events: Collection + + constructor(events: Event[]) { + this.events = collect(events) + } + + getEventsInDateRange(startDate: Date, endDate: Date): Collection { + return this.events.filter((event) => { + const timestamp = event.date.getTime() + return timestamp >= startDate.getTime() + && timestamp <= endDate.getTime() + }) + } + + getEventsByAttendees(minAttendees: number, maxAttendees: number): Collection { + return this.events.whereBetween('attendees', minAttendees, maxAttendees) + } +} +``` + +### Advanced Usage + +#### Performance Metrics + +```typescript +interface Metric { + timestamp: Date + value: number + confidence: number + source: string +} + +class MetricsAnalyzer { + private metrics: Collection + + constructor(metrics: Metric[]) { + this.metrics = collect(metrics) + } + + getMetricsInRange(min: number, max: number): Collection { + return this.metrics + .whereBetween('value', min, max) + .filter(metric => metric.confidence >= 0.8) + } + + getMetricsByConfidence(minConfidence: number, maxConfidence: number): Collection { + return this.metrics.whereBetween('confidence', minConfidence, maxConfidence) + } +} +``` + +#### Grade Analysis + +```typescript +interface StudentGrade { + studentId: string + course: string + score: number + semester: number +} + +class GradeAnalyzer { + private grades: Collection + private readonly gradeRanges = { + A: { min: 90, max: 100 }, + B: { min: 80, max: 89 }, + C: { min: 70, max: 79 }, + D: { min: 60, max: 69 }, + F: { min: 0, max: 59 } + } + + constructor(grades: StudentGrade[]) { + this.grades = collect(grades) + } + + getGradeRange(grade: keyof typeof this.gradeRanges): Collection { + const range = this.gradeRanges[grade] + return this.grades.whereBetween('score', range.min, range.max) + } + + getCustomRange(min: number, max: number): Collection { + return this.grades.whereBetween('score', min, max) + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + value: number + score: number + timestamp: Date +} + +const items = collect([ + { id: 1, value: 100, score: 85, timestamp: new Date() }, + { id: 2, value: 150, score: 92, timestamp: new Date() }, + { id: 3, value: 200, score: 78, timestamp: new Date() } +]) + +// Type-safe range filtering +const valueRange = items.whereBetween('value', 100, 180) +const scoreRange = items.whereBetween('score', 80, 95) + +// TypeScript enforces valid keys and comparable values +// items.whereBetween('invalid', 0, 100) // ✗ TypeScript error +// items.whereBetween('id', 'min', 'max') // ✗ TypeScript error +``` + +## Return Value + +- Returns a new Collection containing items within the specified range +- Range is inclusive of min and max values +- Returns empty collection if no matches found +- Original collection remains unchanged +- Maintains type safety with TypeScript +- Can be chained with other collection methods + +## Common Use Cases + +### 1. Price Filtering + +- Price ranges +- Cost categories +- Budget filtering +- Value ranges + +### 2. Date Ranges + +- Time periods +- Date filtering +- Schedule ranges +- Timeline segments + +### 3. Numeric Ranges + +- Score ranges +- Value spans +- Quantity ranges +- Measurement bounds + +### 4. Grade Systems + +- Score ranges +- Grade boundaries +- Performance bands +- Rating ranges + +### 5. Age Groups + +- Age ranges +- Year groups +- Time spans +- Period filtering + +### 6. Size Categories + +- Dimension ranges +- Size groups +- Weight classes +- Volume spans + +### 7. Performance Metrics + +- Score ranges +- Rating bands +- Performance levels +- Metric bounds + +### 8. Stock Levels + +- Inventory ranges +- Quantity spans +- Stock levels +- Supply bounds + +### 9. Statistical Ranges + +- Value ranges +- Confidence intervals +- Distribution bands +- Probability ranges + +### 10. Resource Usage + +- Usage levels +- Consumption ranges +- Capacity bounds +- Utilization spans diff --git a/docs/api/whereIn.md b/docs/api/whereIn.md new file mode 100644 index 0000000..b63b609 --- /dev/null +++ b/docs/api/whereIn.md @@ -0,0 +1,296 @@ +# WhereIn Method + +The `whereIn()` method filters the collection by a given key and array of values, returning a new collection with all items where the given key's value is contained in the given array. + +## Basic Syntax + +```typescript +collect(items).whereIn(key: keyof T, values: T[key][]): Collection +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from '@stacksjs/ts-collect' + +// Filter by multiple values +const users = collect([ + { id: 1, role: 'admin' }, + { id: 2, role: 'user' }, + { id: 3, role: 'editor' }, + { id: 4, role: 'user' } +]) + +const filtered = users.whereIn('role', ['admin', 'editor']) +console.log(filtered.all()) +// [ +// { id: 1, role: 'admin' }, +// { id: 3, role: 'editor' } +// ] +``` + +### Working with Objects + +```typescript +interface Product { + id: number + category: string + status: 'available' | 'discontinued' | 'out_of_stock' + price: number +} + +const products = collect([ + { id: 1, category: 'electronics', status: 'available', price: 100 }, + { id: 2, category: 'books', status: 'discontinued', price: 20 }, + { id: 3, category: 'electronics', status: 'out_of_stock', price: 150 }, + { id: 4, category: 'clothing', status: 'available', price: 45 } +]) + +// Get products from specific categories +const selectedCategories = products.whereIn('category', ['electronics', 'books']) + +// Get products with specific statuses +const activeProducts = products.whereIn('status', ['available', 'out_of_stock']) +``` + +### Real-world Examples + +#### Order Processing + +```typescript +interface Order { + id: string + status: 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled' + customerId: string + priority: number +} + +class OrderProcessor { + private orders: Collection + + constructor(orders: Order[]) { + this.orders = collect(orders) + } + + getActiveOrders(): Collection { + return this.orders.whereIn('status', ['pending', 'processing', 'shipped']) + } + + getHighPriorityOrders(): Collection { + return this.orders.whereIn('priority', [1, 2]) + } + + getCustomerOrders(customerIds: string[]): Collection { + return this.orders.whereIn('customerId', customerIds) + } +} +``` + +#### Permission System + +```typescript +interface Permission { + userId: string + resource: string + access: 'read' | 'write' | 'admin' | 'none' +} + +class AccessController { + private permissions: Collection + + constructor(permissions: Permission[]) { + this.permissions = collect(permissions) + } + + getResourceUsers(resource: string, accessLevels: string[]): Collection { + return this.permissions + .where('resource', resource) + .whereIn('access', accessLevels) + } + + getUserResources(userId: string, allowedAccess: string[]): Collection { + return this.permissions + .where('userId', userId) + .whereIn('access', allowedAccess) + } +} +``` + +### Advanced Usage + +#### Task Management + +```typescript +interface Task { + id: string + assignee: string + status: 'todo' | 'in_progress' | 'review' | 'done' + priority: 1 | 2 | 3 + tags: string[] +} + +class TaskManager { + private tasks: Collection + + constructor(tasks: Task[]) { + this.tasks = collect(tasks) + } + + getTasksByAssignees(assignees: string[]): Collection { + return this.tasks.whereIn('assignee', assignees) + } + + getActiveTasksByPriority(priorities: number[]): Collection { + return this.tasks + .whereIn('status', ['todo', 'in_progress', 'review']) + .whereIn('priority', priorities) + } + + filterByTags(requiredTags: string[]): Collection { + return this.tasks.filter(task => + requiredTags.some(tag => task.tags.includes(tag)) + ) + } +} +``` + +#### Inventory Filter + +```typescript +interface InventoryItem { + sku: string + warehouse: string + status: 'in_stock' | 'low_stock' | 'out_of_stock' + categories: string[] +} + +class InventoryFilter { + private inventory: Collection + + constructor(inventory: InventoryItem[]) { + this.inventory = collect(inventory) + } + + getItemsByWarehouses(warehouses: string[]): Collection { + return this.inventory.whereIn('warehouse', warehouses) + } + + getItemsByStatus(statuses: string[]): Collection { + return this.inventory.whereIn('status', statuses) + } + + getItemsByCategories(categories: string[]): Collection { + return this.inventory.filter(item => + categories.some(category => item.categories.includes(category)) + ) + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + status: 'active' | 'inactive' | 'pending' + category: string + priority: 1 | 2 | 3 +} + +const items = collect([ + { id: 1, status: 'active', category: 'A', priority: 1 }, + { id: 2, status: 'inactive', category: 'B', priority: 2 }, + { id: 3, status: 'pending', category: 'C', priority: 3 } +]) + +// Type-safe filtering +const filtered = items.whereIn('status', ['active', 'pending']) +const highPriority = items.whereIn('priority', [1, 2]) + +// TypeScript enforces valid keys and values +// items.whereIn('invalid', ['value']) // ✗ TypeScript error +// items.whereIn('status', ['invalid_status']) // ✗ TypeScript error +``` + +## Return Value + +- Returns a new Collection containing items with matching values +- Returns empty collection if no matches found +- Original collection remains unchanged +- Maintains type safety with TypeScript +- Can be chained with other collection methods +- Uses strict equality (===) for value comparison + +## Common Use Cases + +### 1. Status Filtering + +- Multiple status selection +- State filtering +- Condition matching +- Status group filtering + +### 2. Category Selection + +- Multiple category filtering +- Group selection +- Type filtering +- Classification matching + +### 3. User Management + +- Role-based access +- Permission groups +- User type filtering +- Group membership + +### 4. Order Processing + +- Status filtering +- Priority levels +- Order types +- Processing stages + +### 5. Resource Access + +- Permission levels +- Access rights +- Resource groups +- Authorization levels + +### 6. Inventory Management + +- Product categories +- Stock status +- Location groups +- Item classification + +### 7. Task Organization + +- Status groups +- Priority levels +- Assignment groups +- Category filtering + +### 8. Data Classification + +- Type groups +- Category sets +- Classification sets +- Group filtering + +### 9. Event Processing + +- Event types +- Status groups +- Category sets +- Priority levels + +### 10. Configuration Management + +- Environment groups +- Feature sets +- Setting groups +- Configuration sets diff --git a/docs/api/whereNotBetween.md b/docs/api/whereNotBetween.md new file mode 100644 index 0000000..f7546e9 --- /dev/null +++ b/docs/api/whereNotBetween.md @@ -0,0 +1,256 @@ +# whereNotBetween Method + +The `whereNotBetween()` method filters the collection, returning a new collection with all items where the given key's value falls outside the specified minimum and maximum range (exclusive). + +## Basic Syntax + +```typescript +collect(items).whereNotBetween(key: keyof T, min: T[K], max: T[K]): Collection +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from '@stacksjs/ts-collect' + +const numbers = collect([ + { id: 1, value: 10 }, + { id: 2, value: 20 }, + { id: 3, value: 30 }, + { id: 4, value: 40 }, + { id: 5, value: 50 } +]) + +const outsideRange = numbers.whereNotBetween('value', 20, 40) +console.log(outsideRange.all()) +// [ +// { id: 1, value: 10 }, +// { id: 5, value: 50 } +// ] +``` + +### Working with Objects + +```typescript +interface Product { + id: number + name: string + price: number + weight: number +} + +const products = collect([ + { id: 1, name: 'Light Item', price: 25, weight: 0.5 }, + { id: 2, name: 'Medium Item', price: 50, weight: 2.0 }, + { id: 3, name: 'Heavy Item', price: 75, weight: 5.0 } +]) + +// Get products outside standard shipping weight range +const specialShipping = products.whereNotBetween('weight', 1.0, 3.0) +``` + +### Real-world Examples + +#### E-commerce Price Filter + +```typescript +interface Product { + id: string + name: string + price: number + category: string + inStock: boolean +} + +class ProductFilter { + private products: Collection + + constructor(products: Product[]) { + this.products = collect(products) + } + + getPremiumAndBudgetProducts(midRangeMin: number, midRangeMax: number): Collection { + return this.products + .whereNotBetween('price', midRangeMin, midRangeMax) + .filter(product => product.inStock) + } + + getSpecialPricingProducts(): Collection { + // Get products outside normal pricing range for special marketing + return this.products.whereNotBetween('price', 10, 100) + } +} +``` + +#### Inventory Management + +```typescript +interface InventoryItem { + id: string + quantity: number + reorderPoint: number + maxStock: number +} + +class InventoryManager { + private inventory: Collection + + constructor(items: InventoryItem[]) { + this.inventory = collect(items) + } + + getStockAlerts(): Collection { + // Get items with irregular stock levels (too low or too high) + return this.inventory.whereNotBetween('quantity', 10, 100) + } + + getIrregularReorderPoints(): Collection { + // Find items with unusual reorder points + return this.inventory.whereNotBetween('reorderPoint', 5, 50) + } +} +``` + +### Advanced Usage + +#### Order Management System + +```typescript +interface Order { + id: string + total: number + items: number + processingTime: number +} + +class OrderProcessor { + private orders: Collection + + constructor(orders: Order[]) { + this.orders = collect(orders) + } + + getUnusualOrders(): Collection { + // Find orders outside normal processing time + return this.orders.whereNotBetween('processingTime', 1, 48) + } + + getSpecialHandlingOrders(): Collection { + // Orders requiring special handling due to size + return this.orders.whereNotBetween('items', 1, 10) + } + + getCustomPricingOrders(): Collection { + // Orders outside standard pricing range + return this.orders.whereNotBetween('total', 100, 1000) + } +} +``` + +## Type Safety + +```typescript +interface TypedProduct { + id: number + price: number + weight: number + stock: number +} + +const products = collect([ + { id: 1, price: 50, weight: 1.5, stock: 100 }, + { id: 2, price: 150, weight: 2.5, stock: 200 }, + { id: 3, price: 250, weight: 3.5, stock: 300 } +]) + +// Type-safe range filtering +const premiumProducts = products.whereNotBetween('price', 75, 200) +const specialShipping = products.whereNotBetween('weight', 2.0, 3.0) + +// TypeScript enforces valid keys and comparable values +// products.whereNotBetween('invalid', 0, 100) // ✗ TypeScript error +// products.whereNotBetween('id', 'a', 'z') // ✗ TypeScript error +``` + +## Return Value + +- Returns a new Collection containing items where the value is outside the specified range +- Returns empty collection if no matches found +- Original collection remains unchanged +- Maintains type safety with TypeScript +- Can be chained with other collection methods +- Range comparison uses less than or equal to (<=) and greater than or equal to (>=) + +## Common Use Cases + +### 1. E-commerce + +- Filtering premium or budget products +- Identifying items requiring special shipping +- Finding products with unusual stock levels +- Detecting irregular pricing patterns + +### 2. Inventory Management + +- Identifying irregular stock levels +- Finding items with unusual reorder points +- Detecting storage anomalies +- Managing special storage requirements + +### 3. Order Processing + +- Finding orders requiring special handling +- Identifying unusual processing times +- Detecting irregular order sizes +- Managing custom pricing requirements + +### 4. Financial Operations + +- Identifying unusual transactions +- Finding irregular account balances +- Detecting anomalous payment amounts +- Managing special pricing cases + +### 5. Performance Monitoring + +- Finding outlier response times +- Identifying unusual resource usage +- Detecting irregular traffic patterns +- Managing threshold violations + +### 6. Quality Control + +- Identifying out-of-spec measurements +- Finding unusual test results +- Detecting irregular production metrics +- Managing special tolerance cases + +### 7. Time Management + +- Finding irregular processing durations +- Identifying unusual schedule gaps +- Detecting anomalous completion times +- Managing special time allocations + +### 8. Resource Allocation + +- Identifying unusual resource requirements +- Finding irregular usage patterns +- Detecting special allocation needs +- Managing resource exceptions + +### 9. Customer Service + +- Finding unusual response times +- Identifying irregular case durations +- Detecting special handling requirements +- Managing priority exceptions + +### 10. Analytics + +- Identifying statistical outliers +- Finding unusual patterns +- Detecting anomalous metrics +- Managing special analytical cases diff --git a/docs/api/whereNotIn.md b/docs/api/whereNotIn.md new file mode 100644 index 0000000..8ccc2c4 --- /dev/null +++ b/docs/api/whereNotIn.md @@ -0,0 +1,297 @@ +# WhereNotIn Method + +The `whereNotIn()` method filters the collection by a given key and array of values, returning a new collection with all items where the given key's value is not contained in the given array. + +## Basic Syntax + +```typescript +collect(items).whereNotIn(key: keyof T, values: T[K][]): Collection +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from '@stacksjs/ts-collect' + +// Filter excluding specific values +const users = collect([ + { id: 1, role: 'admin' }, + { id: 2, role: 'user' }, + { id: 3, role: 'editor' }, + { id: 4, role: 'user' } +]) + +const nonUsers = users.whereNotIn('role', ['user']) +console.log(nonUsers.all()) +// [ +// { id: 1, role: 'admin' }, +// { id: 3, role: 'editor' } +// ] +``` + +### Working with Objects + +```typescript +interface Product { + id: number + category: string + status: 'active' | 'discontinued' | 'draft' + price: number +} + +const products = collect([ + { id: 1, category: 'electronics', status: 'active', price: 100 }, + { id: 2, category: 'books', status: 'discontinued', price: 20 }, + { id: 3, category: 'electronics', status: 'draft', price: 150 }, + { id: 4, category: 'clothing', status: 'active', price: 45 } +]) + +// Get products excluding specific categories +const nonElectronics = products.whereNotIn('category', ['electronics']) + +// Get non-draft products +const publishedProducts = products.whereNotIn('status', ['draft']) +``` + +### Real-world Examples + +#### Task Management + +```typescript +interface Task { + id: string + status: 'todo' | 'in_progress' | 'review' | 'done' | 'cancelled' + assignee: string + priority: number +} + +class TaskManager { + private tasks: Collection + + constructor(tasks: Task[]) { + this.tasks = collect(tasks) + } + + getActiveTasks(): Collection { + return this.tasks.whereNotIn('status', ['done', 'cancelled']) + } + + getUnassignedTasks(assignedUsers: string[]): Collection { + return this.tasks.whereNotIn('assignee', assignedUsers) + } + + getNonPriorityTasks(priorityLevels: number[]): Collection { + return this.tasks.whereNotIn('priority', priorityLevels) + } +} +``` + +#### User Permission System + +```typescript +interface UserAccess { + userId: string + resource: string + permission: 'read' | 'write' | 'admin' | 'none' +} + +class AccessManager { + private permissions: Collection + + constructor(permissions: UserAccess[]) { + this.permissions = collect(permissions) + } + + getRestrictedUsers(resource: string, excludedPermissions: string[]): Collection { + return this.permissions + .where('resource', resource) + .whereNotIn('permission', excludedPermissions) + } + + getNonAdminAccess(users: string[]): Collection { + return this.permissions + .whereNotIn('userId', users) + .whereNotIn('permission', ['admin']) + } +} +``` + +### Advanced Usage + +#### Content Moderation + +```typescript +interface Content { + id: string + type: string + status: 'draft' | 'pending' | 'published' | 'archived' | 'flagged' + categories: string[] + authorId: string +} + +class ContentModerator { + private content: Collection + + constructor(content: Content[]) { + this.content = collect(content) + } + + getReviewableContent(excludedStatuses: string[]): Collection { + return this.content + .whereNotIn('status', excludedStatuses) + } + + getNonRestrictedContent(excludedCategories: string[]): Collection { + return this.content.filter(item => + !item.categories.some(cat => excludedCategories.includes(cat)) + ) + } + + getContentExcludingAuthors(excludedAuthors: string[]): Collection { + return this.content.whereNotIn('authorId', excludedAuthors) + } +} +``` + +#### Inventory Management + +```typescript +interface StockItem { + sku: string + location: string + status: 'available' | 'reserved' | 'damaged' | 'sold' + categories: string[] +} + +class InventoryManager { + private inventory: Collection + + constructor(inventory: StockItem[]) { + this.inventory = collect(inventory) + } + + getAvailableStock(excludedLocations: string[]): Collection { + return this.inventory + .whereNotIn('location', excludedLocations) + .whereNotIn('status', ['damaged', 'sold']) + } + + getNonRestrictedItems(restrictedCategories: string[]): Collection { + return this.inventory.filter(item => + !item.categories.some(cat => restrictedCategories.includes(cat)) + ) + } + + getProcessableItems(excludedStatuses: string[]): Collection { + return this.inventory.whereNotIn('status', excludedStatuses) + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + status: 'active' | 'inactive' | 'pending' + category: string + priority: 1 | 2 | 3 +} + +const items = collect([ + { id: 1, status: 'active', category: 'A', priority: 1 }, + { id: 2, status: 'inactive', category: 'B', priority: 2 }, + { id: 3, status: 'pending', category: 'C', priority: 3 } +]) + +// Type-safe filtering +const active = items.whereNotIn('status', ['inactive', 'pending']) +const lowPriority = items.whereNotIn('priority', [1, 2]) + +// TypeScript enforces valid keys and values +// items.whereNotIn('invalid', ['value']) // ✗ TypeScript error +// items.whereNotIn('status', ['invalid_status']) // ✗ TypeScript error +``` + +## Return Value + +- Returns a new Collection excluding items with matching values +- Returns empty collection if all items match excluded values +- Original collection remains unchanged +- Maintains type safety with TypeScript +- Can be chained with other collection methods +- Uses strict equality (===) for value comparison + +## Common Use Cases + +### 1. Status Filtering + +- Exclude completed items +- Filter out inactive states +- Remove archived content +- Exclude specific statuses + +### 2. User Management + +- Filter out restricted users +- Exclude specific roles +- Remove inactive accounts +- Filter non-authorized users + +### 3. Content Management + +- Exclude draft content +- Filter out specific types +- Remove restricted categories +- Hide archived items + +### 4. Inventory Control + +- Exclude out-of-stock items +- Filter unavailable products +- Remove discontinued items +- Exclude specific locations + +### 5. Access Control + +- Filter out restricted access +- Exclude specific permissions +- Remove blocked users +- Filter unauthorized access + +### 6. Task Management + +- Exclude completed tasks +- Filter out cancelled items +- Remove specific priorities +- Exclude assigned tasks + +### 7. Data Analysis + +- Exclude outliers +- Filter out categories +- Remove specific types +- Exclude data ranges + +### 8. Resource Management + +- Exclude reserved resources +- Filter out specific types +- Remove unavailable items +- Exclude locations + +### 9. Event Processing + +- Exclude processed events +- Filter out specific types +- Remove cancelled events +- Exclude categories + +### 10. Configuration Management + +- Exclude specific settings +- Filter out environments +- Remove feature flags +- Exclude configurations