Skip to content

Commit ac926df

Browse files
authored
Merge pull request #4 from dhassanali/feature/v2.0-enhancements
feat: Version 2.0 with limit, pluck, unique, groupBy, when methods
2 parents 9e1e18d + d0c4006 commit ac926df

8 files changed

Lines changed: 830 additions & 46 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
composer.lock
2-
vendor
2+
vendor
3+
.idea

CHANGELOG.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Changelog
2+
3+
All notable changes to `one-loop` will be documented in this file.
4+
5+
## [2.0.0] - 2025-11-20
6+
7+
### Added
8+
- **Early Exit Optimization**: New `limit()` and `take()` methods for stopping iteration early
9+
- **Pluck Support**: Extract specific properties with `pluck()` method
10+
- **Unique Items**: Remove duplicates with `unique()` method
11+
- **Group By**: Group items by key or callback with `groupBy()` method
12+
- **Conditional Operations**: New `when()` method for conditional operation chains
13+
- **Filter Method**: Added explicit `filter()` method (complement to existing `reject()`)
14+
- **Laravel Collection Integration**: Automatic `oneLoop()` macro for Laravel Collections
15+
- **Comprehensive Test Suite**: Full PHPUnit test coverage for all features
16+
17+
### Changed
18+
- **Improved Performance**: Optimized internal iteration logic
19+
- **Better Documentation**: Added performance benchmarks and usage guidelines
20+
- **Enhanced README**: Included real-world examples and performance warnings
21+
- **Extended PHP Support**: Now supports PHP 7.2.5 through 8.3
22+
- **Extended Laravel Support**: Now supports Laravel 5.8 through 11.0
23+
24+
### Performance
25+
- Benchmarked with datasets from 1K to 500K records
26+
- Shows 28-35% improvement on large datasets (100K+ records)
27+
- Added performance warnings for small datasets
28+
29+
### Breaking Changes
30+
- None - fully backward compatible with v1.x
31+
32+
## [1.0.0] - 2019
33+
34+
### Added
35+
- Initial release
36+
- Basic `reject()` and `map()` operations
37+
- Single-loop optimization for array operations
38+
- Helper function `one_loop()`
39+
- Support for Laravel Collections and arrays

README.md

Lines changed: 208 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,28 @@
55
[![License](https://badgen.net/packagist/license/hassan/one-loop)](https://packagist.org/packages/hassan/one-loop)
66
[![Coverage Status](https://badgen.net/codecov/c/github/dhassanali/one-loop)](https://codecov.io/github/dhassanali/one-loop)
77

8-
A Laravel/PHP Package for Minimizing Collection/Array Iterations
8+
A Laravel/PHP Package for Minimizing Collection/Array Iterations - **optimized for large datasets (100,000+ records)**.
9+
10+
## 📊 Performance Benchmarks
11+
12+
Real-world performance tests show significant improvements with large datasets:
13+
14+
| Dataset Size | Operations | Standard PHP | OneLoop | Improvement |
15+
|-------------|-----------|--------------|---------|-------------|
16+
| 500,000 | Complex (3+ ops) | 163.03 ms | 105.84 ms | **35% faster**|
17+
| 500,000 | Simple (2 ops) | 226.32 ms | 161.79 ms | **29% faster**|
18+
| 100,000 | Complex (3+ ops) | 25.83 ms | 18.54 ms | **28% faster**|
19+
| 10,000 | Any | 0.98 ms | 1.84 ms | 88% slower ⚠️ |
20+
| 1,000 | Any | 0.08 ms | 0.19 ms | 137% slower ⚠️ |
21+
22+
### ⚠️ Performance Warning
23+
24+
**This package is optimized for large datasets.** It provides significant performance improvements when:
25+
- Processing **100,000+ records**
26+
- Chaining **2-3+ operations** (filter, map, reject, etc.)
27+
- Running **batch jobs** or **data processing tasks**
28+
29+
For small datasets (< 50,000 records), standard PHP array functions or Laravel Collections will be faster due to lower overhead.
930

1031
## Installation
1132

@@ -17,7 +38,9 @@ composer require hassan/one-loop
1738

1839
## Usage
1940

20-
``` php
41+
### Basic Example
42+
43+
```php
2144
$users = App\User::all();
2245

2346
$ids = one_loop($users)->reject(static function ($user) {
@@ -29,6 +52,188 @@ $ids = one_loop($users)->reject(static function ($user) {
2952
->apply();
3053
```
3154

32-
### Security
55+
## 🆕 New Features in v2.0
56+
57+
### Early Exit with `limit()` / `take()`
58+
59+
Stop processing once you have enough results:
60+
61+
```php
62+
// Get first 100 active users
63+
$users = one_loop($allUsers)
64+
->filter(fn($user) => $user->active)
65+
->limit(100)
66+
->apply();
67+
68+
// Alias: take()
69+
$users = one_loop($allUsers)
70+
->filter(fn($user) => $user->active)
71+
->take(100)
72+
->apply();
73+
```
74+
75+
### Extract Properties with `pluck()`
76+
77+
```php
78+
// Pluck by property name
79+
$emails = one_loop($users)
80+
->pluck('email')
81+
->apply();
82+
83+
// Pluck with callback
84+
$fullNames = one_loop($users)
85+
->pluck(fn($user) => $user->first_name . ' ' . $user->last_name)
86+
->apply();
87+
```
88+
89+
### Remove Duplicates with `unique()`
90+
91+
```php
92+
// Unique values
93+
$uniqueDepartments = one_loop($employees)
94+
->pluck('department')
95+
->unique()
96+
->apply();
97+
98+
// Unique by key
99+
$uniqueUsers = one_loop($users)
100+
->unique('email')
101+
->apply();
102+
```
103+
104+
### Group Items with `groupBy()`
105+
106+
```php
107+
// Group by property
108+
$byDepartment = one_loop($employees)
109+
->groupBy('department')
110+
->apply();
111+
112+
// Group by callback
113+
$byAgeGroup = one_loop($users)
114+
->groupBy(function($user) {
115+
if ($user->age < 30) return 'young';
116+
if ($user->age < 50) return 'middle';
117+
return 'senior';
118+
})
119+
->apply();
120+
```
121+
122+
### Conditional Operations with `when()`
123+
124+
```php
125+
$shouldFilterActive = true;
126+
127+
$result = one_loop($users)
128+
->when($shouldFilterActive, function($loop) {
129+
$loop->filter(fn($user) => $user->active);
130+
})
131+
->map(fn($user) => $user->id)
132+
->apply();
133+
```
134+
135+
### Laravel Collection Integration
136+
137+
OneLoop automatically integrates with Laravel Collections:
138+
139+
```php
140+
use Illuminate\Support\Collection;
141+
142+
// Use on any Collection
143+
$result = User::all()
144+
->oneLoop()
145+
->filter(fn($user) => $user->active)
146+
->map(fn($user) => $user->id)
147+
->apply();
148+
```
149+
150+
## 🎓 Available Methods
151+
152+
### Filtering
153+
- `filter(callable $callback)` - Keep items that match condition
154+
- `reject(callable $callback)` - Remove items that match condition
155+
156+
### Transformation
157+
- `map(callable $callback)` - Transform each item
158+
- `pluck(string|callable $value)` - Extract specific property
159+
160+
### Uniqueness & Grouping
161+
- `unique(?string|callable $key = null)` - Remove duplicates
162+
- `groupBy(string|callable $groupBy)` - Group by key or callback
163+
164+
### Limiting
165+
- `limit(int $limit)` - Limit results (early exit)
166+
- `take(int $count)` - Alias for limit()
167+
168+
### Conditional
169+
- `when(bool $condition, callable $callback, ?callable $default = null)` - Conditional operations
170+
171+
### Execution
172+
- `apply()` - Execute all queued operations and return results
173+
174+
## 📊 When to Use OneLoop
175+
176+
### ✅ Perfect For:
177+
- **Large datasets** (100K+ records)
178+
- **Batch processing** jobs
179+
- **ETL operations**
180+
- **Data migrations**
181+
- **Complex filtering** with 2-3+ operations
182+
- **Report generation**
183+
- **Product catalog filtering** (e-commerce)
184+
- **Customer segmentation** (marketing)
185+
186+
### ❌ Not Ideal For:
187+
- Small datasets (< 50K records)
188+
- Single operation (just one filter or map)
189+
- Real-time web requests with small result sets
190+
- When microseconds matter with tiny datasets
191+
192+
## 🎯 Real-World Example
193+
194+
```php
195+
// E-commerce: Process large product catalog
196+
$products = Product::all() // 500,000 products
197+
->oneLoop()
198+
->filter(fn($p) => $p->active)
199+
->reject(fn($p) => $p->stock <= 0)
200+
->when($categoryFilter, fn($loop) =>
201+
$loop->filter(fn($p) => in_array($p->category_id, $categoryFilter))
202+
)
203+
->map(fn($p) => [
204+
'id' => $p->id,
205+
'name' => $p->name,
206+
'price' => $p->price * 0.9 // 10% discount
207+
])
208+
->limit(1000)
209+
->apply();
210+
211+
// Result: 35% faster than standard operations!
212+
```
213+
214+
## 🧪 Testing
215+
216+
```bash
217+
composer test
218+
```
219+
220+
## 📝 Changelog
221+
222+
Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
223+
224+
## 🤝 Contributing
225+
226+
Contributions are welcome! Please feel free to submit a Pull Request.
227+
228+
## 🔒 Security
33229

34230
If you discover any security related issues, please email hello@hassan-ali.me instead of using the issue tracker.
231+
232+
## 📜 License
233+
234+
The MIT License (MIT). Please see [License File](LICENSE) for more information.
235+
236+
## 🙏 Credits
237+
238+
- [Hassan Ali](https://github.com/dhassanali)
239+
- [All Contributors](../../contributors)

composer.json

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
"one-loop",
77
"collect",
88
"collection",
9-
"laravel-collection"
9+
"laravel-collection",
10+
"performance",
11+
"optimization"
1012
],
1113
"homepage": "https://github.com/dhassanali/one-loop",
1214
"license": "MIT",
@@ -18,12 +20,12 @@
1820
}
1921
],
2022
"require": {
21-
"php": "^7.2.5",
22-
"illuminate/support": "^5.8|^6.0|^7.0",
23-
"illuminate/contracts": "^5.8|^6.0|^7.0"
23+
"php": "^7.2.5|^8.0|^8.1|^8.2|^8.3",
24+
"illuminate/support": "^5.8|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
25+
"illuminate/contracts": "^5.8|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0"
2426
},
2527
"require-dev": {
26-
"phpunit/phpunit": "^8.5"
28+
"phpunit/phpunit": "^8.5|^9.0|^10.0"
2729
},
2830
"autoload": {
2931
"files": [
@@ -43,5 +45,12 @@
4345
},
4446
"config": {
4547
"sort-packages": true
48+
},
49+
"extra": {
50+
"laravel": {
51+
"providers": [
52+
"Hassan\\OneLoop\\OneLoopServiceProvider"
53+
]
54+
}
4655
}
47-
}
56+
}

0 commit comments

Comments
 (0)