368 lines
8.6 KiB
Markdown
368 lines
8.6 KiB
Markdown
# Platform Collections
|
|
|
|
A Dart implementation of Laravel's Collection class, providing fluent wrappers for working with arrays of data.
|
|
|
|
## Features
|
|
|
|
- Fluent interface for array operations
|
|
- Rich set of collection manipulation methods
|
|
- Support for transformations and aggregations
|
|
- List interface implementation
|
|
- Type-safe operations
|
|
- Laravel-compatible dot notation support
|
|
- Wildcard operations and special segments
|
|
- Lazy collection support
|
|
- Higher order message passing
|
|
|
|
## Usage
|
|
|
|
```dart
|
|
import 'package:platform_collections/platform_collections.dart';
|
|
|
|
// Create a collection
|
|
final numbers = Collection([1, 2, 3, 4, 5]);
|
|
|
|
// Basic operations
|
|
numbers.avg(); // 3.0
|
|
numbers.max(); // 5
|
|
numbers.min(); // 1
|
|
|
|
// Transformations
|
|
numbers.filter((n) => n.isEven); // [2, 4]
|
|
numbers.mapItems((n) => n * 2); // [2, 4, 6, 8, 10]
|
|
numbers.chunk(2); // [[1, 2], [3, 4], [5]]
|
|
```
|
|
|
|
## Key Features
|
|
|
|
### Creation and Basic Operations
|
|
|
|
```dart
|
|
// Create empty collection
|
|
final empty = Collection<int>();
|
|
|
|
// Create from items
|
|
final items = Collection([1, 2, 3]);
|
|
|
|
// Create range
|
|
final range = Collection.range(1, 5); // [1, 2, 3, 4, 5]
|
|
|
|
// Get all items
|
|
final list = items.all(); // Returns unmodifiable List
|
|
```
|
|
|
|
### Transformations
|
|
|
|
```dart
|
|
// Filter items
|
|
collection.filter((item) => item.isEven);
|
|
|
|
// Map items
|
|
collection.mapItems((item) => item * 2);
|
|
|
|
// Chunk into smaller collections
|
|
collection.chunk(2);
|
|
|
|
// Chunk by condition
|
|
collection.chunkWhile((current, next) => current < next);
|
|
|
|
// Flatten nested collections
|
|
Collection([[1, 2], [3, 4]]).flatten(); // [1, 2, 3, 4]
|
|
|
|
// Get unique items
|
|
collection.unique();
|
|
|
|
// Split into parts
|
|
collection.split(3); // Split into 3 parts
|
|
collection.splitIn(2); // Split in half
|
|
```
|
|
|
|
### Collection Operations
|
|
|
|
```dart
|
|
// Check for existence
|
|
collection.contains(value);
|
|
collection.containsStrict(value); // Strict comparison
|
|
|
|
// Find differences
|
|
collection.diff(other);
|
|
collection.diffAssoc(other);
|
|
|
|
// Get items relative to another
|
|
collection.before(value); // Get item before
|
|
collection.after(value); // Get item after
|
|
|
|
// Multiply values
|
|
collection.multiply(3); // Repeat each item 3 times
|
|
|
|
// Combine with another collection
|
|
keys.combine(values); // Create map from two collections
|
|
|
|
// Count occurrences
|
|
collection.countBy(); // Count by value
|
|
collection.countBy((item) => item.type); // Count by callback
|
|
|
|
// Get or set value
|
|
collection.getOrPut('key', () => computeValue());
|
|
```
|
|
|
|
### Aggregations
|
|
|
|
```dart
|
|
// Calculate average
|
|
collection.avg();
|
|
collection.avg((item) => item.value); // With callback
|
|
|
|
// Group items
|
|
final grouped = collection.groupBy((item) => item.category);
|
|
|
|
// Find maximum/minimum
|
|
collection.max();
|
|
collection.min();
|
|
|
|
// Get single items
|
|
collection.firstOrFail(); // Throws if empty
|
|
collection.sole(); // Throws if not exactly one item
|
|
```
|
|
|
|
### Working with Objects
|
|
|
|
```dart
|
|
final users = Collection([
|
|
{'id': 1, 'name': 'John', 'role': 'admin'},
|
|
{'id': 2, 'name': 'Jane', 'role': 'user'},
|
|
]);
|
|
|
|
// Group by a key
|
|
final byRole = users.groupBy((user) => user['role']);
|
|
|
|
// Get unique by key
|
|
final uniqueRoles = users.unique((user) => user['role']);
|
|
|
|
// Convert to Map
|
|
final map = users.toMap(
|
|
(user) => user['id'],
|
|
(user) => user['name'],
|
|
);
|
|
```
|
|
|
|
### Lazy Collections
|
|
|
|
```dart
|
|
// Create lazy collection
|
|
final lazy = LazyCollection(() sync* {
|
|
for (var i = 0; i < 1000000; i++) {
|
|
yield i;
|
|
}
|
|
});
|
|
|
|
// Operations are evaluated lazily
|
|
final result = lazy
|
|
.filter((n) => n.isEven)
|
|
.take(5)
|
|
.toList(); // [0, 2, 4, 6, 8]
|
|
|
|
// Efficient for large datasets
|
|
final transformed = lazy
|
|
.filter((n) => n.isEven)
|
|
.map((n) => n * 2)
|
|
.takeWhile((n) => n < 100);
|
|
```
|
|
|
|
### Higher Order Messages
|
|
|
|
```dart
|
|
// Access properties
|
|
collection.map('name'); // Same as map((item) => item.name)
|
|
collection.sum('quantity'); // Sum of quantity property
|
|
|
|
// Call methods
|
|
collection.map('toString'); // Call toString() on each item
|
|
collection.filter('isActive'); // Filter by isActive property/method
|
|
|
|
// Dynamic operations
|
|
collection['property']; // Access property on each item
|
|
collection.invoke('method', args); // Call method with args
|
|
```
|
|
|
|
### Dot Notation Support
|
|
|
|
The package includes Laravel-compatible dot notation support for working with nested data structures:
|
|
|
|
```dart
|
|
// Get nested values
|
|
final data = {
|
|
'users': [
|
|
{'name': 'John', 'profile': {'age': 30}},
|
|
{'name': 'Jane', 'profile': {'age': 25}}
|
|
]
|
|
};
|
|
|
|
// Get value using dot notation
|
|
dataGet(data, 'users.0.name'); // 'John'
|
|
dataGet(data, 'users.*.name'); // ['John', 'Jane']
|
|
|
|
// Set nested values
|
|
dataSet(data, 'users.0.profile.age', 31);
|
|
|
|
// Remove values
|
|
dataForget(data, 'users.0.profile');
|
|
|
|
// Fill missing values
|
|
dataFill(data, 'users.0.email', 'john@example.com');
|
|
```
|
|
|
|
### Special Segments
|
|
|
|
Support for special segment notation in dot paths:
|
|
|
|
```dart
|
|
// First/Last item access
|
|
dataGet(data, 'users.{first}.name'); // First user's name
|
|
dataGet(data, 'users.{last}.name'); // Last user's name
|
|
|
|
// Wildcard operations
|
|
dataGet(data, 'users.*.profile.age'); // All users' ages
|
|
dataSet(data, 'users.*.active', true); // Set all users active
|
|
```
|
|
|
|
### Helper Functions
|
|
|
|
```dart
|
|
// Get first/last elements
|
|
head([1, 2, 3]); // 1
|
|
last([1, 2, 3]); // 3
|
|
|
|
// Create collection from iterable
|
|
final collection = collect([1, 2, 3]);
|
|
|
|
// Get value from factory
|
|
final value = value(() => computeValue());
|
|
```
|
|
|
|
### List Operations
|
|
|
|
The Collection class implements Dart's `ListMixin`, providing all standard list operations:
|
|
|
|
```dart
|
|
final list = Collection(['a', 'b', 'c']);
|
|
|
|
// Add/remove items
|
|
list.add('d');
|
|
list.remove('b');
|
|
|
|
// Access by index
|
|
list[0] = 'A';
|
|
final first = list[0];
|
|
|
|
// Standard list methods
|
|
list.length;
|
|
list.isEmpty;
|
|
list.reversed;
|
|
```
|
|
|
|
### Helper Methods
|
|
|
|
```dart
|
|
// Get random items
|
|
collection.random(); // Single random item
|
|
collection.random(3); // Multiple random items
|
|
|
|
// Join items
|
|
collection.joinWith(', '); // Custom join with separator
|
|
|
|
// Cross join collections
|
|
final colors = Collection(['red', 'blue']);
|
|
final sizes = Collection(['S', 'M']);
|
|
colors.crossJoin([sizes]); // All combinations
|
|
```
|
|
|
|
## Important Notes
|
|
|
|
1. The Collection class is generic and maintains type safety:
|
|
```dart
|
|
final numbers = Collection<int>([1, 2, 3]);
|
|
final strings = Collection<String>(['a', 'b', 'c']);
|
|
```
|
|
|
|
2. Most methods return a new Collection instance, keeping the original unchanged:
|
|
```dart
|
|
final original = Collection([1, 2, 3]);
|
|
final doubled = original.mapItems((n) => n * 2); // Original unchanged
|
|
```
|
|
|
|
3. The class implements `ListMixin`, so it can be used anywhere a List is expected:
|
|
```dart
|
|
void processList(List<int> list) {
|
|
// Works with Collection<int>
|
|
}
|
|
```
|
|
|
|
4. Dot notation operations maintain type safety and handle null values gracefully:
|
|
```dart
|
|
dataGet(data, 'missing.path', defaultValue); // Returns defaultValue
|
|
```
|
|
|
|
5. Lazy collections are memory efficient for large datasets:
|
|
```dart
|
|
// Only processes what's needed
|
|
LazyCollection(generator)
|
|
.filter(predicate)
|
|
.take(5); // Stops after finding 5 items
|
|
```
|
|
|
|
## Example
|
|
|
|
See the [example](example/platform_collections_example.dart) for a complete demonstration of all features.
|
|
|
|
## Features in Detail
|
|
|
|
### Transformation Methods
|
|
- `filter()` - Filter items using a callback
|
|
- `mapItems()` - Transform items using a callback
|
|
- `chunk()` - Split into smaller collections
|
|
- `chunkWhile()` - Chunk by condition
|
|
- `flatten()` - Flatten nested collections
|
|
- `unique()` - Get unique items
|
|
- `split()` - Split into parts
|
|
- `splitIn()` - Split into equal parts
|
|
|
|
### Collection Operations
|
|
- `contains()` - Check for existence
|
|
- `containsStrict()` - Strict comparison
|
|
- `diff()` - Find differences
|
|
- `diffAssoc()` - Find differences with keys
|
|
- `before()` - Get previous item
|
|
- `after()` - Get next item
|
|
- `multiply()` - Repeat items
|
|
- `combine()` - Combine with values
|
|
- `countBy()` - Count occurrences
|
|
- `getOrPut()` - Get or set value
|
|
|
|
### Aggregation Methods
|
|
- `avg()` - Calculate average
|
|
- `max()` - Get maximum value
|
|
- `min()` - Get minimum value
|
|
- `groupBy()` - Group items by key
|
|
- `firstOrFail()` - Get first or throw
|
|
- `sole()` - Get single item
|
|
|
|
### Higher Order Methods
|
|
- Property access
|
|
- Method calls
|
|
- Dynamic operations
|
|
|
|
### Helper Functions
|
|
- `collect()` - Create collection from iterable
|
|
- `dataGet()` - Get value using dot notation
|
|
- `dataSet()` - Set value using dot notation
|
|
- `dataFill()` - Fill missing values
|
|
- `dataForget()` - Remove values
|
|
- `head()` - Get first element
|
|
- `last()` - Get last element
|
|
- `value()` - Get value from factory
|
|
|
|
### List Operations
|
|
- Standard list methods (`add`, `remove`, etc.)
|
|
- Index access (`[]`, `[]=`)
|
|
- List properties (`length`, `isEmpty`, etc.)
|