platform/packages/collections
2024-12-15 18:34:28 -07:00
..
doc add: adding laravel style collections, macroable, support packages 2024-12-15 18:34:28 -07:00
example add: adding laravel style collections, macroable, support packages 2024-12-15 18:34:28 -07:00
lib add: adding laravel style collections, macroable, support packages 2024-12-15 18:34:28 -07:00
test add: adding laravel style collections, macroable, support packages 2024-12-15 18:34:28 -07:00
.gitignore add: adding collections package 2024-12-15 16:26:11 -07:00
analysis_options.yaml add: adding laravel style collections, macroable, support packages 2024-12-15 18:34:28 -07:00
CHANGELOG.md add: adding collections package 2024-12-15 16:26:11 -07:00
LICENSE.md add: adding collections package 2024-12-15 16:26:11 -07:00
pubspec.yaml add: adding laravel style collections, macroable, support packages 2024-12-15 18:34:28 -07:00
README.md add: adding laravel style collections, macroable, support packages 2024-12-15 18:34:28 -07:00

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

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

// 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

// 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

// 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

// 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

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

// 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

// 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:

// 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:

// 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

// 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:

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

// 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:

    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:

    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:

    void processList(List<int> list) {
      // Works with Collection<int>
    }
    
  4. Dot notation operations maintain type safety and handle null values gracefully:

    dataGet(data, 'missing.path', defaultValue);  // Returns defaultValue
    
  5. Lazy collections are memory efficient for large datasets:

    // Only processes what's needed
    LazyCollection(generator)
        .filter(predicate)
        .take(5);  // Stops after finding 5 items
    

Example

See the example 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.)