Skip to content

Latest commit

 

History

History
2895 lines (2196 loc) · 122 KB

README.ru.md

File metadata and controls

2895 lines (2196 loc) · 122 KB

PHP Коллекции

Библиотека для удобной работы с массивами данных различных структур с использованием функционального подхода. В основе лежат структуры данных, такие как: Список, Карта, Множество, Стек, Очередь.

Для обхода и преобразования коллекций используется stream api (Stream), который обеспечивает функциональный подход.

Читать на других языках: English

Системные требования

PHP 7.1+

Установка

Установить и использовать библиотеку в собственном проекте можно использовав менеджер зависимостей Composer

composer require worksolutions/php-collections

Пример использования

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

// Отобрать элементы по фильтру
CollectionFactory::from([1, 2, 3])
    ->stream()
    ->filter(Predicates::greaterThan(1))
    ->getCollection(); // Collection [2, 3]

// Распечатать все файлы в директории
CollectionFactory::fromIterable(new DirectoryIterator(__DIR__))
    ->stream()
    ->each(static function (SplFileInfo $fileInfo) {
        echo $fileInfo->getFilename() . "\n";
    });

Основные концепции

В основе использования библиотеки лежит последовательный подход обработки и преобразования данных. Создание некого конвейера преобразования, где можно последовательно выполнять некие шаги. Каждый шаг отвечает только за свой небольшой кусочек работы. В этом случае шаги можно переиспользовать так как они являются атомарными.

Фундаментально библиотека состоит из нескольких частей, это:

  • Структуры данных. Каждая имеет свою особенность, выраженную при помощи интерфейса и описания к нему, и реализацию. При этом реализации поведения структур данных могут быть разные.
  • Фабрика создания коллекции. Имеет множество статических методов для удобного создания коллекций.
  • Потоки обхода коллекций. Предназначен для обхода и преобразования коллекций, при этом каждое преобразование создает новый экземпляр коллекции.
  • Набор функций обхода и преобразования. Состоит из заранее подготовленных конструкторов функций для удобного использования в момент обхода. На их примере можно создать и использовать собственные функции более специфичные для вашей предметной области.

Структуры данных

В основе библиотеки лежат самые популярные структуры данных которые являются самодостаточными для использования без каких-либо посторонних библиотек и классов. Все остальные части библиотеки основываются на эти структуры, в частности на интерфейс Collection. Все структуры данных коллекций содержат множество элементов с которыми можно проводить основные процедуры, такие как: обход, преобразование, агрегирования и т.д.

Коллекция (Collection)

[↑ Структуры данных]

Основной базовый интерфейс коллекций. Все структуры данных кроме карт (Map) реализуют этот интерфейс, весь дополнительный функционал (Фабрики, Потоки обхода) используют данный интерфейс. Для поддержания универсальности в своих приложениях рекомендуется использовать именно интерфейс Collection, но только в том случае если это не противоречит назначению использования структуры.

Коллекции доступны для обхода при помощи цикла foreach.

Методы интерфейса

add - Добавление элемента в коллекцию

[↑ Коллекция (Collection)]

add($element: mixed): bool;

Добавляет элемент в конец коллекции. Возвращает true в случае успешного ответа или false при неудаче.

use WS\Utils\Collections\CollectionFactory;

$collection = CollectionFactory::from([1, 2]); // [1, 2]
$collection->add(10); // [1, 2] -> [1, 2, 10];

addAll - Добавление множества элементов в коллекцию

[↑ Коллекция (Collection)]

addAll($elements: iterable): bool;

Добавляет множества элементов в конец коллекции. Возвращает true в случае успешного ответа или false при неудаче.

use WS\Utils\Collections\CollectionFactory;

$collection = CollectionFactory::from([1, 2]); // [1, 2]
$collection->add([10, 11, 12]); // true
$collection->toArray(); // [1, 2] -> [1, 2, 10, 11, 12];

merge - Слияние коллекций

[↑ Коллекция (Collection)]

merge($collection: Collection): bool;

Метод объединяет текущую коллекцию с переданной. Возвращает true в случае успешного ответа или false при неудаче.

use WS\Utils\Collections\CollectionFactory;

$collection = CollectionFactory::from([1, 2]); // [1, 2]
$mergingCollection = CollectionFactory::from([11, 12]); // [11, 12]
$collection->merge($mergingCollection); // true
$collection->toArray(); // [1, 2, 10, 11, 12];

clear - Удаление всех элементов коллекции

[↑ Коллекция (Collection)]

clear(): void;

Метод удаляет все элементы коллекции.

use WS\Utils\Collections\CollectionFactory;

$collection = CollectionFactory::from([1, 2]); // [1, 2]
$collection->clear(); // null
$collection->toArray(); // [];

remove - Удаление элемента коллекции

[↑ Коллекция (Collection)]

remove($element: mixed): bool;

Удаление конкретного элемента в коллекции. Метод возвращает признак удаления элемента. Если элемента не существовало, вернется false.

use WS\Utils\Collections\CollectionFactory;

$collection = CollectionFactory::from([1, 2, 3]); // [1, 2, 3]
$collection->remove(2); // true
$collection->remove(4); // false
$collection->toArray(); // [1, 3];

contains - Проверка на существование элемента в коллекции

[↑ Коллекция (Collection)]

contains($element: mixed): bool;

Проверка наличия конкретного элемента в коллекции. Если элемента не существует, вернется false.

use WS\Utils\Collections\CollectionFactory;

$collection = CollectionFactory::from([1, 2, 3]); // [1, 2, 3]
$collection->contains(2); // true
$collection->contains(4); // false

equals - Сравнение двух коллекций на эквивалентность

[↑ Коллекция (Collection)]

equals($collection: Collection): bool;

Метод проверяет, что переданная коллекция эквивалентна текущей, это означает что все элементы одной коллекции содержатся в другой коллекции и количество элементов равно. В случае неравенства коллекций, вернется false.

use WS\Utils\Collections\HashSet;

$set1 = new HashSet([1, 2, 3]);
$set2 = new HashSet([3, 2, 1]);
$set3 = new HashSet([3, 2]);

$set1->equals($set2); // true
$set2->equals($set1); // true
$set1->equals($set3); // false

size - Получение количества элементов в коллекции

[↑ Коллекция (Collection)]

size(): int;

Метод возвращает число элементов в коллекции. Если коллекция пустая - 0.

use WS\Utils\Collections\CollectionFactory;

$collection = CollectionFactory::from([1, 2, 3]); // [1, 2, 3]
$collection->size(); // 3

$emptyCollection = CollectionFactory::from([]);
$emptyCollection->size(); // false

isEmpty - Проверка коллекции на пустоту

[↑ Коллекция (Collection)]

isEmpty(): bool;

Метод возвращает признак пустой коллекции. Если в коллекции существуют элементы, вернется false.

use WS\Utils\Collections\CollectionFactory;

$collection = CollectionFactory::from([1, 2, 3]); // [1, 2, 3]
$collection->isEmpty(); // false

$emptyCollection = CollectionFactory::from([]);
$emptyCollection->isEmpty(); // true

toArray - Получение элементов коллекции в виде массива

[↑ Коллекция (Collection)]

toArray(): array;

Метод индексированный массив состоящий из элементов коллекции, порядок следования элементов зависит от внутреннего представления.

use WS\Utils\Collections\CollectionFactory;

$collection = CollectionFactory::from([1, 2, 3]); // [1, 2, 3]
$collection->toArray(); // [1, 2, 3]

$emptyCollection = CollectionFactory::from([]);
$emptyCollection->toArray(); // []

copy - Получение копии коллекции

[↑ Коллекция (Collection)]

copy(): Collection;

Метод возвращает точную копию коллекции. Коллекции - мутабельны. Это означает, что применение методов модификации изменяет коллекцию, для гарантии неизменности коллекции рекомендуется применять метод копирования.

use WS\Utils\Collections\CollectionFactory;

$collection = CollectionFactory::from([1, 2, 3]); // [1, 2, 3]
$copyOfCollection = $collection->copy(); // Collection

$copyOfCollection === $collection; // false

stream - Получение потока обхода коллекции (Stream)

[↑ Коллекция (Collection)]

stream(): Stream;

Метод объект который реализует интерфейс обхода коллекции (Stream). Поток обхода коллекции является очень мощным инструментом и в большинстве случаев при разработке приходится иметь дело именно с ним. [Подробнее...](#Поток обхода коллекции)

use WS\Utils\Collections\CollectionFactory;

$collection = CollectionFactory::from([1, 2, 3]); // [1, 2, 3]
$collection
    ->stream()
    ->each(static function (int $el) {var_export($el);}); // 1 2 3

Обход коллекции при помощи цикла foreach

[↑ Коллекция (Collection)]

Коллекции доступны для обхода при в цикле foreach. Порядок перебора коллекции зависит от внутренней реализации конкретного класса.

use WS\Utils\Collections\CollectionFactory;

$collection = CollectionFactory::from([1, 2, 3]); // [1, 2, 3]

foreach($collection as $item) {
    var_export($item);
}

Список (ListSequence)

[↑ Структуры данных]

Списком является структура данных в которой строго определен порядок элементов. Списки с одинаковым набором элементов и разной их последовательностью не равны. Интерфейс ListSequence расширяет интерфейс Collection.

Интерфейс списка (ListSequence) расширяет интерфейсы: Collection

Интерфейс списка (ListSequence) реализуют классы: ArrayList, ImmutableList

Методы интерфейса

get - Получение элемента по порядковому индексу

[↑ Список (ListSequence)]

get($index: int): mixed;

Метод возвращает элемент по индексу. Если по индексу элемента не существует, вернет null. Первый элемент списка имеет индекс 0.

use WS\Utils\Collections\ArrayList;

$list = ArrayList::of(1, 2);

$list->get(0); // 1
$list->get(1); // 2
$list->get(2); // null

set - Замена элемента списка

[↑ Список (ListSequence)]

set($element: mixed, $index: int): mixed;

Метод заменяет элемент по индексу. Возвращает значение элемента который был заменен текущим методом. Если происходит попытка заменить не существующий элемент, OutOfRangeException будет выброшен.

use WS\Utils\Collections\ArrayList;

$list = ArrayList::of(1, 2);

$list->set(3, 0); // 1
$list->set(4, 1); // 2
$list->set(4, 2); // OutOfRangeException

indexOf - Получение порядкового индекса элемента

[↑ Список (ListSequence)]

indexOf($element: mixed): ?int;

Метод возвращает первый индекс найденного элемента. В случае отсутствия значения в списке, вернется null.

use WS\Utils\Collections\ArrayList;

$list = ArrayList::of(1, 2, 1, 3);

$list->indexOf(1); // 0
$list->indexOf(2); // 1
$list->indexOf(4); // null

lastIndexOf - Получение порядкового индекса последнего подходящего элемента

[↑ Список (ListSequence)]

lastIndexOf($element: mixed): ?int;

Метод возвращает последний индекс найденного элемента. В случае отсутствия значения в списке, вернется null.

use WS\Utils\Collections\ArrayList;

$list = ArrayList::of(1, 2, 1, 3);

$list->indexOf(1); // 2
$list->indexOf(2); // 1
$list->indexOf(3); // null

removeAt - Удаление элемента по индексу

[↑ Список (ListSequence)]

removeAt(int $index): mixed;

Метод удаляет элемент по индексу, элементы находящиеся после удаленного индекса перемещаются ближе к началу на одну позицию. Возвращает значение удаленного элемента. В случае отсутствия элемента по индексу вернется null.

use WS\Utils\Collections\ArrayList;

$list = ArrayList::of(1, 2, 1, 3);

$list->removeAt(1); // 2
$list->toArray(); // [1, 1, 3]

Множество (Set)

[↑ Структуры данных]

Множество содержит только уникальные элементы, порядок следования элементов может быть любым. То есть добавление элемента методом add не гарантирует его последнее место среди остальных элементов при итерировании и в случае наличия элемента с таким же значением, последний не добавится в множество.

Уникальность определяется значением, а для объектов либо уникальностью конкретного объекта, либо в случае если объект реализует интерфейс HashCodeAware уникальностью результата вызова метода getHashCode(): string;.

Интерфейс множества (Set) расширяет интерфейсы: Collection

Интерфейс множества (Set) реализуют классы: HashSet

Очередь (Queue)

[↑ Структуры данных]

Такая структура данных как очередь удобна для последовательной обработки данных в порядке поступления. Она обладает удобными методами добавления и потребления элементов. Первый элемент, который попал в очередь - первым ее и покинет.

Интерфейс очереди (Queue) расширяет интерфейсы: Collection

Интерфейс очереди (Queue) реализуют классы: ArrayQueue

Методы интерфейса

offer - Вставка элемента в очередь

[↑ Очередь (Queue)]

offer($element): bool;

Метод добавляет элемент в конец очереди. Возвращает false если элемент не был добавлен, возможно в случае ограниченной очереди.

use WS\Utils\Collections\ArrayQueue;

$queue = ArrayQueue::of(1, 2);

$queue->offer(3); // [1, 2, 3]
$queue->peek(); // 3

poll - Получение элемента и удаление его из очереди

[↑ Очередь (Queue)]

poll(): mixed;

Метод возвращает элемент и удаляет его из начала очереди. В случае отсутствия элементов в очереди будет выброшено исключение RuntimeException.

use WS\Utils\Collections\ArrayQueue;

$queue = ArrayQueue::of(1, 2);

$queue->peek(); // 2
$queue->poll(); // [1]
$queue->peek(); // 1

peek - Получение элемента без удаления его из очереди

[↑ Очередь (Queue)]

poll(): mixed;

Метод возвращает элемент. Очередь при этом не изменяется, элемент остается на своем месте. В случае отсутствия элементов в очереди будет выброшено исключение RuntimeException.

use WS\Utils\Collections\ArrayQueue;

$queue = ArrayQueue::of(1, 2, 3);

$queue->peek(); // 2
$queue->size(); // 3

Стек (Stack)

[↑ Структуры данных]

Стек является структурой данных логика работы которой противоположна логике работы очереди. Первый элемент попавшей в стек будет первым и извлечен из него.

Интерфейс стека (Stack) расширяет интерфейсы: Collection

Интерфейс стека (Stack) реализуют классы: ArrayStack

Методы интерфейса

push - Добавление элемента

[↑ Стек (Stack)]

push($element: mixed): bool;

Метод добавляет элемент на вершину стека. Возвращает false если элемент не был добавлен, возможно в случае ограничений.

use WS\Utils\Collections\ArrayStack;

$queue = ArrayStack::of(1, 2);

$queue->push(3); // [1, 2, 3]
$queue->peek(); // 3

pop - Получение последнего добавленного элемента

[↑ Стек (Stack)]

pop(): mixed;

Метод возвращает элемент с вершины стека. На вершину стека остается элемент добавленный перед полученным. В случае отсутствия элементов в стеке будет выброшено исключение RuntimeException.

use WS\Utils\Collections\ArrayStack;

$queue = ArrayStack::of(1, 2, 3); // [1, 2, 3]

$queue->pop(); // 3
$queue->pop(); // 2
$queue->push(4); // [1, 4]
$queue->pop(); // 4
$queue->peek(); // 1

peek - Получение последнего добавленного элемента без модификации стека

[↑ Стек (Stack)]

peek(): mixed;

Метод возвращает элемент который расположен на вершине стека. В случае отсутствия элементов в стеке будет выброшено исключение RuntimeException.

use WS\Utils\Collections\ArrayStack;

$queue = ArrayStack::of(1, 2, 3); // [1, 2, 3]

$queue->pop(); // 3
$queue->peek(); // 3
$queue->peek(); // 3

$queue->pop(); // 2
$queue->pop(); // 1
$queue->peek(); // RuntimeException

Карта (Map)

[↑ Структуры данных]

Карта представляет отображение или иначе говоря словарь, где каждый элемент представляет пару "ключ-значение". Ключи карты уникальны по значению, если это объекты, то уникальность достигается либо уникальностью ссылки на объект, либо в случае если объект реализует интерфейс HashCodeAware уникальностью результата вызова метода getHashCode(): string;.

Интерфейс карты (Map) расширяет интерфейсы: IteratorAggregate

Интерфейс карты (Map) реализуют классы: HashMap

Методы интерфейса

put - Добавление пары ключ/значение

[↑ Карта (Map)]

put($key: mixed, $value: mixed): bool;

Метод добавляет пару ключ/значение в объект структуры. Возвращает false если элемент не был добавлен, возможно в случае ограничений. Как ключом так и значением могут быть данные скалярных типов, массивы и объекты.

use WS\Utils\Collections\HashMap;

$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);

foreach ($map as $k => $v) {
    var_dump($k); // one | two
    var_dump($v); // 1   | 2
}

get - Получение значения пары по ключу

[↑ Карта (Map)]

get($key): mixed;

Метод возвращает значение пары по ключу key. В случае, если значения нет вернется null.

use WS\Utils\Collections\HashMap;

$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);

$map->get('one'); // 1
$map->get('three'); // null

keys - Получение коллекции ключей карты

[↑ Карта (Map)]

keys(): Collection<mixed>;

Метод возвращает коллекцию состоящую из всех ключей карты.

use WS\Utils\Collections\HashMap;

$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);

foreach ($map->keys() as $k) {
    var_dump($k); // one | two
}

values - Получение коллекции значений карты

[↑ Карта (Map)]

values(): Collection<mixed>;

Метод возвращает коллекцию состоящую из всех значений пар карты.

use WS\Utils\Collections\HashMap;

$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);

foreach ($map->keys() as $v) {
    var_dump($v); // 1 | 2
}

remove - Удаление пары по ключу

[↑ Карта (Map)]

remove($key: mixed): bool;

Метод удаляет пару из карты по ключу key.

use WS\Utils\Collections\HashMap;

$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);

$map->remove('one');
foreach ($map->keys() as $v) {
    var_dump($v); // 2
}

containsKey - Признак наличия пары по ключу

[↑ Карта (Map)]

containsKey($key: mixed): bool;

Метод возвращает признак наличия пары с ключом key.

use WS\Utils\Collections\HashMap;

$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);

$map->containsKey('one'); // true

containsValue - Признак наличия пары по значению

[↑ Карта (Map)]

containsValue($value: mixed): bool;

Метод возвращает признак наличия пары со значением value.

use WS\Utils\Collections\HashMap;

$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);

$map->containsValue(1); // true
$map->containsValue(3); // false

size - Количество пар в карте

[↑ Карта (Map)]

size(): int;

Метод возвращает количество пар.

use WS\Utils\Collections\HashMap;

$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);

$map->size(); // 2

$emptyMap = new HashMap();
$map->size(); // 0

stream - Получение потока обхода коллекции пар ключ/значение (Stream)

[↑ Карта (Map)]

stream(): Stream;

Метод возвращает объект, который реализует интерфейс обхода (Stream). Элементами коллекции потока являются объекты пар ключ/значение KeyPair. [Подробнее...](#Поток обхода коллекции)

use \WS\Utils\Collections\HashMap;
use \WS\Utils\Collections\MapEntry;

$map = new HashMap();

$map->put('one', 1);
$map->put('two', 2);
$map->put('tree', 3);

$map->stream()->each(static function (MapEntry $mapEntry) {
    var_export($mapEntry->getKey()); // 'one', 'two', 'three'
    var_export($mapEntry->getKey()); // 1    , 2    , 3
});

Обход объекта map при помощи цикла foreach

[↑ Карта (Map)]

Объект типа Map можно итерировать в цикле foreach. В этом случае ключи и значения будут оригинальные. Таким образом ключом может быть любой тип кроме массива.

use \WS\Utils\Collections\HashMap;

$map = new HashMap();

$map->put(new SplObjectStorage(), 1);
$map->put(null, 2);
$map->put(false, 3);
$map->put(true, 4);
$map->put(0, 5);

foreach($map as $key => $value) {
    var_export($key);   // object of SplObjectStorage class| null| false| true| 0 
    var_export($value); // 1                               | 2   | 3    | 4   | 5
}

Фабрика создания коллекции

[↑ В начало]

Фабрики CollectionFactory/MapFactory позволяют создавать объекты коллекций без использования конструктора конкретной реализации, а так же обладает другими удобными методами создания объектов коллекций. На данный момент основной структурой библиотеки являются ArrayList, HashMap, HashSet, которые и порождается фабрикой в статических методах.

Пример использования фабрики

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Consumers;

CollectionFactory::numbers(10)
    ->stream()
    ->each(Consumers::dump()); // dumps int(0), int(1), ...

Методы фабрики создания коллекции

CollectionFactory::from - Генерирование коллекции из массива элементов

[↑ Фабрика создания коллекции]

from($values: array): Collection

Метод создает коллекцию элементы которой состоят из элементов переданного массива.

На данный момент реализацией коллекции является ArrayList, в будущем конкретная реализация может поменяться, при вызове данного метода стоит опираться только на интерфейс Collection.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Consumers;

CollectionFactory::from([1 ,2, 3])
    ->stream()
    ->each(Consumers::dump()); // dumps int(1), int(2), int(3)

CollectionFactory::fromIterable - Генерирование коллекции при помощи любой итерируемой величины

[↑ Фабрика создания коллекции]

fromIterable($iterable: iterable): Collection

Метод создает коллекцию элементы которой состоят из элементов переданного итератора.

На данный момент реализацией коллекции является ArrayList, в будущем конкретная реализация может поменяться, при вызове данного метода стоит опираться только на интерфейс Collection.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Consumers;
use WS\Utils\Collections\Functions\Converters;

CollectionFactory::fromIterable(new DirectoryIterator(__DIR__))
    ->stream()
    ->map(Converters::toPropertyValue('filename'))
    ->each(Consumers::dump()); // Dumps strings with filenames

CollectionFactory::numbers - Генерирование коллекции состоящей из элементов последовательности целых чисел

[↑ Фабрика создания коллекции]

numbers($from: int, $to: ?int): Collection

Метод создает коллекцию, элементы которой состоят из последовательности целых чисел [$from .. $to]. Если параметр $to не передан, вернется коллекция [0 .. $from].

На данный момент реализацией коллекции является ArrayList, в будущем конкретная реализация может поменяться, при вызове данного метода стоит опираться только на интерфейс Collection.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Consumers;

CollectionFactory::numbers(10, 15)
    ->stream()
    ->each(Consumers::dump()); // Dumps  [10, 11, 12, 13, 14, 15]

CollectionFactory::generate - Генерирование коллекции при помощи генератора

[↑ Фабрика создания коллекции]

generate($times: int, $generator: ?callable): Collection

Метод создает коллекцию размерности $times, элементы которой состоят из значений результатов вызова генератора $generator.

На данный момент реализацией коллекции является ArrayList, в будущем конкретная реализация может поменяться, при вызове данного метода стоит опираться только на интерфейс Collection. Если нужно конкретный тип экземпляра коллекций - нужно использовать конструкторы реализаций или их статические методы.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Consumers;

CollectionFactory::generate(3, static function () {
        return random_int(0, 10);
    })
    ->stream()
    ->each(Consumers::dump()); // Dumps for example [9, 7, 2]

MapFactory::fromIterable - Генерирование карты при помощи любого итерируемого значения

[↑ Фабрика создания коллекции]

MapFactory::fromIterable($iterable: iterable): Map

Метод создает объект карты из любого итерируемого объекта.

use WS\Utils\Collections\MapFactory;

MapFactory::fromIterable(['a' => 1, 'b' => 2])
    ->keys() // ['a', 'b']
;

MapFactory::assoc - Генерирование карты при помощи ассоциативного массива

[↑ Фабрика создания коллекции]

MapFactory::assoc(array $assocArray): Map

Метод создает объект карты из ассоциативного массива.

use WS\Utils\Collections\MapFactory;

MapFactory::assoc(['a' => 1, 'b' => 2])
    ->keys() // ['a', 'b']
;

Потоки обхода коллекций

[↑ В начало]

Для более удобного обхода и преобразования коллекций необходимо использовать потоки обхода коллекций (Stream). В основном все вычисления должны производится через stream. Для получения потока нужно вызвать метод коллекции Collection::stream().

Обработка коллекции при помощи stream происходит через выполнения функций, интерфейсы которых должны соответствовать назначению обхода/преобразования. Всего их шесть:

  • Предикат (Predicate). Используется для фильтра элементов filter, элемент остается в коллекции потока (stream) в случае если предикат вызванный для данного элемента вернет булевое положительное значение. Библиотека уже содержит некоторые подготовленные предикаты.
  • Конвертер (Converter). Функции этого типа используются для преобразования коллекции потока map. Конвертер должен вернуть значение которое по некоторому признаку соответствует переданному элементу коллекции. Библиотека уже содержит некоторые подготовленные конвертеры.
  • Потребитель (Consumer). Функции потребителей не изменяют коллекцию потока, а используются для ее обхода each. Переданная функция будет вызвана для каждого элемента коллекции, результат выполнения функции не учитывается. Библиотека уже содержит некоторые подготовленные потребители.
  • Функции сравнения (Comparator). Компораторы участвуют в сортировке элементов для определения порядка сортировки двух значений. Должна возвращать целое, которое меньше, равно или больше нуля, если первый аргумент является соответственно меньшим, равным или большим, чем второй. php.net usort. Библиотека уже содержит некоторые подготовленные функции сравнения.
  • Преобразователь (Reorganizer). Функции преобразователей преобразуют одну коллекцию в другую reorganize не изменяя при этом объекта потока. Преобразования необходимы когда нужно получить итоговую коллекцию не просто преобразовывая один элемент в другой, а сформировать новую коллекцию основываясь на всей информации исходной коллекции. Примером могут служить методы перемешивания shuffle элементов или формирования порций chunk. Библиотека уже содержит некоторые подготовленные преобразователи.
  • Функции сбора данных (Collector). Функции сбора данных применяются к потоку при помощи метода collect, по сути результат выполнения функций этой группы и будет являться результатом выполнения потока. Метод collect является терминальным, то есть вызовом этого метода поток обрывается.

Все потоки принадлежат интерфейсу Stream, это означает что описание интерфейса гарантирует его корректное исполнение вне зависимости от конкретной реализации, исключения лишь составляют частные случаи поведения потоков (when).

Stream`s гарантируют, что после каждого метода модификации метод getCollection будет возвращать разные экземпляры объектов, что является надежным способом с точки зрения безопасности для поддержания иммутабельности при преобразовании.

Методы интерфейса потока

each - Обход элементов коллекции

[↑ Потоки обхода коллекций]

each($consumer: <fn($element: mixed, $index: int): void>): Stream;

Метод применяет к каждому элементу коллекции потока, функцию $consumer. Результат выполнения функции не учитывается. Вызов метода each не изменяет коллекцию потока, но в то же время получает доступ к каждому элементу в коллекции.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Consumers;

CollectionFactory::numbers(10)
    ->stream()
    ->each(Consumers::dump()) // dumps each element
    ->each(static function ($el) { // prints strings 0, 1, 2, 3
        echo $el."\n"; 
    })
;

walk - Ограниченный обход элементов коллекции

[↑ Потоки обхода коллекций]

walk($consumer: <fn($element: mixed, $index: int): false|void>, $limit: ?int): Stream;

Метод применяет к каждому элементу коллекции потока, функцию $consumer, так же как и в методе each. Результат выполнения функции не учитывается. Вызов метода each не изменяет коллекцию потока, но в то же время получает доступ к каждому элементу в коллекции.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Consumers;

CollectionFactory::numbers(10)
    ->stream()
    ->walk(Consumers::dump(), 5) // dumps only first 5 elements: 0, 1, 2, 3, 4
    ->walk(static function ($el) { // prints strings 0, 1, 2, 3. Method will be called only 5 times
        if ($el === 4) {
            return false;
        }
        echo $el."\n";
    })
;

filter - Фильтрация элементов коллекции

[↑ Потоки обхода коллекций]

filter($predicate: <fn($element: mixed): bool>): Stream;

Метод применяет к каждому элементу коллекции потока, функцию $predicate. В случае если вызов предиката с элементов вернет отрицательный результат - false, 0, '', [], элемент исключается из коллекции.

use WS\Utils\Collections\CollectionFactory;

CollectionFactory::numbers(10)
    ->stream()
    ->filter(static function (int $el): bool {
        return $el % 2 === 0;
    })
    ->getCollection() // returns only first 5 elements: 0, 2, 4, 6, 8
;

map - Отражение элементов коллекции потока

[↑ Потоки обхода коллекций]

map($converter: <fn($element: mixed): mixed>): Stream;

Метод применяет к каждому элементу коллекции потока, подменяет переданные элементы коллекции на результаты выполнения функции.

use WS\Utils\Collections\CollectionFactory;

CollectionFactory::numbers(10)
    ->stream()
    ->map(static function (int $el): int {
        return $el * 10;
    })
    ->getCollection() // returns 0, 10, 20, 30, 40, 50, 60, 70, 80, 90
;

reorganize - Преобразование коллекции потока

[↑ Потоки обхода коллекций]

reorganize($reorganizer: <fn($collection: Collection): Collection>): Stream;

Метод применяет $reorganizer к внутренней коллекции, затем заменяет внутреннюю коллекцию на результат вызова метода. Необходим когда следует выполнить преобразования основываясь на данных полной коллекции.

use WS\Utils\Collections\ArrayStack;
use WS\Utils\Collections\Collection;
use WS\Utils\Collections\CollectionFactory;

CollectionFactory::numbers(10)
    ->stream()
    // reverse collection 
    ->reorganize(static function (Collection $collection): Collection {
        $stack = new ArrayStack();
        foreach ($collection as $item) {
            $stack->push($item);
        }
        $reversed = CollectionFactory::empty();
        while (!$stack->isEmpty()) {
            $reversed->add($stack->pop());
        }
        return $reversed;
    })
    ->getCollection()
;

collect - Сбор данных коллекции

[↑ Потоки обхода коллекций]

collect($collector: <fn ($collection: Collection): mixed>): mixed;

Метод применяет $collector к внутренней коллекции и возвращает результат. Необходим, когда необходимо выполнить финальное действие над коллекцией с использованием потока. Терминальный метод.

use WS\Utils\Collections\Collection;
use WS\Utils\Collections\CollectionFactory;

$sumOfElements = CollectionFactory::numbers(10)
    ->stream()
    // get sum of collection elements
    ->collect(static function (Collection $collection): int {
        $res = 0;
        foreach ($collection as $item) {
            $res += $item;
        }
        return $res;
    })
;

sort - Сортировка элементов коллекции

[↑ Потоки обхода коллекций]

sort($comparator: <fn($a: mixed, $b: mixed): int>): Stream;

Метод сортирует элементы согласно работе $comparator (компаратора). Компоратор определяет порядок сортировки двух значений. Должен возвращать целое, которое меньше, равно или больше нуля, если первый аргумент является соответственно меньшим, равным или большим, чем второй. php.net usort

use WS\Utils\Collections\CollectionFactory;

$sortedCollection = CollectionFactory::generate(10, static function (): int {
        return random_int(0, 100);
    })
    ->stream()
    // get sorted collection
    ->sort(static function (int $a, int $b): int {
        return $a <=> $b;
    })
    ->getCollection()
;

sortDesc - Сортировка элементов коллекции в обратном порядке

[↑ Потоки обхода коллекций]

sort($comparator: <fn($a: mixed, $b: mixed): int>): Stream;

Метод сортирует элементы согласно работе $comparator (компаратора), но в отличии от обычной функции сортировки элемнты будут выстроены по убыванию. Компоратор определяет порядок сортировки двух значений. Должен возвращать целое, которое меньше, равно или больше нуля, если первый аргумент является соответственно меньшим, равным или большим, чем второй. php.net usort

use WS\Utils\Collections\CollectionFactory;

$sortedDescendentCollection = CollectionFactory::generate(10, static function (): int {
        return random_int(0, 100);
    })
    ->stream()
    // get sorted collection in the reverse order
    ->sortDesc(static function (int $a, int $b): int {
        return $a <=> $b;
    })
    ->getCollection()
;

sortBy - Сортировка элементов коллекции по значению

[↑ Потоки обхода коллекций]

sortBy($extractor: <fn($el: mixed): scalar>): Stream;

Метод сортирует элементы согласно полученному значению функции $extractor для каждого элемента. Функция должна вернуть скалярное значение для возможности независимой оптимизированной сортировки. Аналогично работает метод сортировки по значению в обратном порядке sortByDesc.

use WS\Utils\Collections\CollectionFactory;

class Container {
    private $value;

    public function __construct($value) {
        $this->value = $value;
    }
    
    public function getValue() {
        return $this->value;
    }
}

$sortedCollection = CollectionFactory::generate(10, static function (): Container {
        return new Container(random_int(0, 100));
    })
    ->stream()
    // get sorted collection
    ->sortBy(static function (Container $container): int {
        return $container->getValue();
    })
    ->getCollection()
;

reduce - Сокращение коллекции в единое значение

[↑ Потоки обхода коллекций]

reduce($accumulator: <fn($el: mixed, $carry: mixed): mixed>): mixed;

Метод приводит коллекцию к единому значению. Функции передаются значения $el итерируемого элемента и результат вызова этой же функции на предыдущем элементе $carry. В первой итерации $carry === null. Терминальный метод.

use WS\Utils\Collections\CollectionFactory;

$sumOfCollection = CollectionFactory::numbers(10)
    ->stream()
    // get sum of collection elements
    ->reduce(static function (int $el, ?int $carry = null): int {
        return $carry + $el;
    })
;

when - Ограничение модификации потока по условию

[↑ Потоки обхода коллекций]

when($condition: bool): Stream;

Метод ограничивает модификацию при невыполнении условия $condition и все методы модификации и обхода не будут вызываться. Обратный метод - always.

Блокируемые методы:

  • each
  • walk
  • filter
  • reorganize
  • map
  • sort
  • sortBy
  • sortDesc
  • sortDescBy
  • reverse
  • limit
use WS\Utils\Collections\Collection;
use WS\Utils\Collections\CollectionFactory;

$randomElementSizeCollection = CollectionFactory::numbers(random_int(0, 20));

$onlyTenElements = $randomElementSizeCollection
    ->stream()
    // get collection elements only 10 items
    ->when($randomElementSizeCollection->size() > 10)
    ->limit(10)
    ->when($randomElementSizeCollection->size() < 10)
    ->reorganize(static function (Collection $collection) {
        for ($i = $collection->size(); $i < 10; $i++ ) {
            $collection->add($i);
        }
        return $collection;
    })
;

always - Отмена ограничений модификации потока

[↑ Потоки обхода коллекций]

always(): Stream;

В случае если поток был заблокирован ранее для модификаций через условие when, метод always отменяет ограничения на дальнейший вызов модифицирующих методов.

use WS\Utils\Collections\CollectionFactory;

$collection = CollectionFactory::numbers(20);

$onlyTenElements = $collection
    ->stream()
    // get collection elements only 10 items
    ->when($collection->size() > 5)
    ->limit(5)
    ->always()
    ->map(static function (int $el): int {
        return $el * 10;
    })
    ->getCollection() // [0, 10, 20, 30, 40]
;

getCollection - Получение коллекции потока

[↑ Потоки обхода коллекций]

getCollection(): Collection;

Метод возвращает коллекцию с учетом ранее выполненных преобразований. Даже если в потоке будут еще вызваны методы преобразования, полученная коллекция останется не измененной. Терминальный метод.

use WS\Utils\Collections\CollectionFactory;

$stream = CollectionFactory::numbers(10)
    ->stream();

$collection1 = $stream
    ->map(static function (int $el): int{
        return $el * 10;
    })
    ->getCollection()
;

$collection2 = $stream
    ->filter(static function (int $el): bool {
        return $el > 50;
    })
    ->getCollection()
;

$collection1->size() === $collection2->size(); // false

$collection2->toArray(); // [60, 70, 80, 90]

allMatch - Полное совпадение всех элементов по предикату

[↑ Потоки обхода коллекций]

allMatch($predicate: <fn($el: mixed): bool>): bool;

Метод вернет true, если все вызовы $predicate над элементами коллекции будут истинными (true). Терминальный метод.

use WS\Utils\Collections\CollectionFactory;

CollectionFactory::numbers(10)
    ->stream()
    ->allMatch(static function (int $el): bool {
        return $el >= 1;
    }) // false, 0 is less than 1
;

anyMatch - Частичное совпадение всех элементов по предикату

[↑ Потоки обхода коллекций]

anyMatch(callable $predicate): bool;

Метод вернет true, если хотя бы один вызов $predicate над элементами коллекции будет истинным (true). Терминальный метод.

use WS\Utils\Collections\CollectionFactory;

CollectionFactory::numbers(10)
    ->stream()
    ->anyMatch(static function (int $el): bool {
        return $el > 0;
    }) // true, [1, 2, 3, 4, 5, 6, 7, 8, 9] are grate than 0
;

findAny - Получение произвольного элемента коллекции

[↑ Потоки обхода коллекций]

findAny(): mixed;

Метод вернет произвольный элемент коллекции, либо null, если коллекция пустая. Не гарантирует того что элемент выбирается в случайном порядке. Терминальный метод.

use WS\Utils\Collections\CollectionFactory;

CollectionFactory::numbers(10)
    ->stream()
    ->findAny() // for example - 5
;

findFirst - Получение первого элемента коллекции

[↑ Потоки обхода коллекций]

findFirst(): mixed;

Метод вернет первый элемент коллекции , либо null, если коллекция пустая. Терминальный метод.

use WS\Utils\Collections\CollectionFactory;

CollectionFactory::numbers(10) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
    ->stream()
    ->findFirst() // 0
;

findLast - Получение последнего элемента коллекции

[↑ Потоки обхода коллекций]

findLast(): mixed;

Метод вернет последний элемент коллекции , либо null, если коллекция пустая. Терминальный метод.

use WS\Utils\Collections\CollectionFactory;

CollectionFactory::numbers(10) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
    ->stream()
    ->findLast() // 9
;

min - Получение минимального элемента коллекции

[↑ Потоки обхода коллекций]

min($comparator: <fn($a: mixed, $b: mixed): int>): mixed;

Метод вернет наименьший элемент коллекции согласно сравнению функции компоратора, либо null, если коллекция пустая. Терминальный метод.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Reorganizers;

CollectionFactory::numbers(10) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
    ->stream()
    ->reorganize(Reorganizers::shuffle())
    ->min(static function (int $a, int $b): int {
        return $a <=> $b;
    }) // 0
;

max - Получение максимального элемента коллекции

[↑ Потоки обхода коллекций]

max($comparator: <fn($a: mixed, $b: mixed): int>): mixed;

Метод вернет наибольший элемент коллекции согласно сравнению функции компоратора, либо null, если коллекция пустая. Терминальный метод.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Reorganizers;

CollectionFactory::numbers(10) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
    ->stream()
    ->reorganize(Reorganizers::shuffle())
    ->max(static function (int $a, int $b): int {
        return $a <=> $b;
    }) // 9
;

reverse - Расположить элементы коллекции в обратном порядке

[↑ Потоки обхода коллекций]

reverse(): Stream;

Метод преобразует порядок элементов в обратную последовательность.

use WS\Utils\Collections\CollectionFactory;

CollectionFactory::numbers(10) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
    ->stream()
    ->reverse()
    ->getCollection() // [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
;

limit - Сократить коллекцию до указанного размера

[↑ Потоки обхода коллекций]

limit(int $size): Stream;

Метод сокращает количество элементов до указанного размера. В случае, если количество элементов уже меньше чем указано в ограничении $size, количество элементов останется прежним.

use WS\Utils\Collections\CollectionFactory;

CollectionFactory::numbers(10) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
    ->stream()
    ->reverse()
    ->getCollection() // [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
;

Набор функций обхода и преобразования

[↑ В начало]

Библиотека содержит конструкторы наиболее популярных функций, которые инициируют функции для из работы через потоки обхода и преобразования с заранее подготовленными параметрами. Например:

use \WS\Utils\Collections\Functions\Predicates;

$equal10Predicate = Predicates::equal(10);

$equal10Predicate(11); // false
$equal10Predicate(10); // true

Вызов конструктор функции Predicates::equal(10) вернет функцию сравнения входного параметра со значением 10.

Функции применяемые в библиотеке разделены на следующие типы:

Каждый тип функции должен иметь соответствующий интерфейс для использования в определенных методах потоков.

Predicates Предикаты

[↑ Набор функций обхода и преобразования]

Группа конструкторов функций которые используются для фильтрации коллекции потока. Все методы возвращают проинициализированные функции с интерфейсом: <Fn($el: mixed): bool>. Предикаты также позволяют работать со свойствами объектов. К примеру под свойством объекта myPropety подразумевается наличие публичного свойства в объекте с названием myProperty либо наличие методе геттера - getMyProperty.

lock - Блокировка

[↑ Predicates Предикаты]

lock(): Closure; \\ <Fn($el: mixed): bool>

Метод инициирует функцию, которая на любой набор входных данных - будет возвращать false. По сути метод порождает функцию блокирования потока.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

$lockFunction = Predicates::lock();
CollectionFactory::numbers(1, 10)
    ->stream()
    ->filter($lockFunction)
    ->getCollection()
    ->isEmpty() // true
;

notResistance - Пропуск всех значений

[↑ Predicates Предикаты]

notResistance(): Closure; \\ <Fn($el: mixed): bool>

Метод инициирует функцию, которая на любой набор входных данных - будет возвращать true.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

$passFunction = Predicates::notResistance();
CollectionFactory::numbers(1, 10)
    ->stream()
    ->filter($passFunction)
    ->getCollection()
    ->size() // 10
;

notNull - проверка значений на пустоту

[↑ Predicates Предикаты]

notNull(): Closure; \\ <Fn($el: mixed): bool>

Метод инициирует функцию, которая на любой набор входных данных - будет возвращать true.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

$notNullPassFunction = Predicates::notNull();
CollectionFactory::from([1, 10, null])
    ->stream()
    ->filter($notNullPassFunction)
    ->getCollection()
    ->size() // 2
;

eachEven - Пропуск элементов чётных вызовов

[↑ Predicates Предикаты]

eachEven(): Closure; \\ <Fn($el: mixed): bool>

Метод инициирует функцию, которая каждый четный вызов - будет возвращать true и, соответственно, в остальных случаях - false.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

$evenPassFunction = Predicates::eachEven();
CollectionFactory::from([1, 2, 3, 4, null, false])
    ->stream()
    ->filter($evenPassFunction)
    ->getCollection()
    ->toArray() // 2, 4, false
;

nth - Пропуск элементов кратных вызовов

[↑ Predicates Предикаты]

nth($number: int): Closure; \\ <Fn($el: mixed): bool>

Метод инициирует функцию, которая каждый $number вызов - будет возвращать true и, соответственно, в остальных случаях - false.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

$thirdPassFunction = Predicates::nth(3);
CollectionFactory::from([1, 2, 3, 4, null, false])
    ->stream()
    ->filter($thirdPassFunction)
    ->getCollection()
    ->toArray() // 3, false
;

equal - Проверка на эквивалентность

[↑ Predicates Предикаты]

equal($value: mixed): Closure; \\ <Fn($el: mixed): bool>

Метод инициирует функцию, которая возвращает истинное значение при совпадении элемента коллекции со значением $value.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

CollectionFactory::from([1, 2, 3, 4, null, false])
    ->stream()
    ->filter(Predicates::equal(3))
    ->findFirst() // 3
;

lockDuplicated - Блокировка значений дубликатов

[↑ Predicates Предикаты]

lockDuplicated(): Closure; \\ <Fn($el: mixed): bool>

Метод инициирует функцию, которая возвращает истинное значение только для вызовов с уникальными элементами.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

CollectionFactory::from([3, 2, 3, 4, null, 3])
    ->stream()
    ->filter(Predicates::lockDuplicated())
    ->getCollection()
    ->toArray() // [3, 2, 4, null]
;

lessThan - Проверка значения на условие "меньше"

[↑ Predicates Предикаты]

lessThan($value: scalar): Closure; \\ <Fn($el: scalar): bool>

Метод инициирует функцию сравнения элементов со значением $value.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

CollectionFactory::from([1, 2, 3, 4, null, 3])
    ->stream()
    ->filter(Predicates::lessThan(4))
    ->getCollection()
    ->toArray() // [1, 2, 3, null, 3]
;

lessOrEqual - Проверка значения на условие "меньше либо равно"

[↑ Predicates Предикаты]

lessOrEqual($value: scalar): Closure; \\ <Fn($el: scalar): bool>

Метод инициирует функцию сравнения элементов со значением $value.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

CollectionFactory::from([1, 2, 3, 4, null, 3])
    ->stream()
    ->filter(Predicates::lessOrEqual(2))
    ->getCollection()
    ->toArray() // [1, 2, null]
;

greaterThan - Проверка значения на условие "больше"

[↑ Predicates Предикаты]

greaterThan($value: scalar): Closure; \\ <Fn($el: mixed): bool>

Метод инициирует функцию сравнения элементов со значением $value.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

CollectionFactory::from([1, 2, 3, 4, null, 3])
    ->stream()
    ->filter(Predicates::greaterThan(2))
    ->getCollection()
    ->toArray() // [3, 4, 3]
;

greaterOrEqual - Проверка значения на условие "больше либо равно"

[↑ Predicates Предикаты]

greaterOrEqual($value: scalar): Closure; \\ <Fn($el: mixed): bool>

Метод инициирует функцию сравнения элементов со значением $value.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

CollectionFactory::from([1, 2, 3, 4, null, 3])
    ->stream()
    ->filter(Predicates::greaterOrEqual(2))
    ->getCollection()
    ->toArray() // [2, 3, 4, 3]
;

not - Проверка значения на неравенство

[↑ Predicates Предикаты]

not($value: mixed): Closure; \\ <Fn($el: mixed): bool>

Метод инициирует функцию проверки неравенства элементов коллекции со значением $value.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

CollectionFactory::from([1, 2, 3, 4, null, 3])
    ->stream()
    ->filter(Predicates::not(3))
    ->getCollection()
    ->toArray() // [1, 2, 4, null]
;

in - Проверка значения на нахождение во множестве

[↑ Predicates Предикаты]

in($values: array): Closure; \\ <Fn($el: mixed): bool>

Метод инициирует функцию проверки нахождения элементов во множестве $values.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

CollectionFactory::from([1, 2, 3, 4, null, 3])
    ->stream()
    ->filter(Predicates::in([null, 3]))
    ->getCollection()
    ->toArray() // [3, null, 3]
;

notIn - Проверка значения на отсутствие во множестве

[↑ Predicates Предикаты]

notIn($values: array): Closure; \\ <Fn($el: mixed): bool>

Метод инициирует функцию проверки отсутствия элементов во множестве $values.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

CollectionFactory::from([1, 2, 3, 4, null, 3])
    ->stream()
    ->filter(Predicates::notIn([null, 3]))
    ->getCollection()
    ->toArray() // [1, 2, 4]
;

where - Проверка свойства объекта на эквивалентность

[↑ Predicates Предикаты]

where($property: string, $value: mixed): Closure; \\ <Fn($el: mixed): bool>

Метод инициирует функцию проверки свойства объекта элемента на равенство значению $value.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

class ValueObject {
    private $value;
    public function __construct($value) {
        $this->value = $value;
    }
    
    public function getValue() {
        return $this->value;
    }
}

$c = 0;
CollectionFactory::generate(5, static function () use (& $c) {
        return new ValueObject($c++);
    })
    ->stream()
    ->filter(Predicates::where('value', 0))
    ->getCollection()
    ->isEmpty() // false
;

whereNot - Проверка свойства объекта на неравенство

[↑ Predicates Предикаты]

whereNot($property: string, $value: mixed): Closure; \\ <Fn($el: mixed): bool>

Метод инициирует функцию проверки свойства объекта элемента на неравенство значению $value.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

class ValueObject {
    private $value;
    public function __construct($value) {
        $this->value = $value;
    }
    
    public function getValue() {
        return $this->value;
    }
}

$c = 0;
CollectionFactory::generate(5, static function () use (& $c) {
        return new ValueObject($c++);
    })
    ->stream()
    ->filter(Predicates::whereNot('value', 0))
    ->getCollection()
    ->toArray() // [#1, #2, #3, #4]
;

whereIn - Проверка свойства объекта на нахождение во множестве

[↑ Predicates Предикаты]

whereIn($property: string, $values: array): Closure; \\ <Fn($el: mixed): bool>

Метод инициирует функцию проверки нахождения значения свойства объекта во множестве $values.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

class ValueObject {
    private $value;
    public function __construct($value) {
        $this->value = $value;
    }
    
    public function getValue() {
        return $this->value;
    }
}

$c = 0;
CollectionFactory::generate(5, static function () use (& $c) {
        return new ValueObject($c++);
    })
    ->stream()
    ->filter(Predicates::whereIn('value', [0, 4, 9]))
    ->getCollection()
    ->toArray() // [#0, #4]
;

whereNotIn - Проверка свойства объекта на отсутствие во множестве

[↑ Predicates Предикаты]

whereNotIn($property: string, $values: array): Closure; \\ <Fn($el: mixed): bool>

Метод инициирует функцию проверки отсутствия значения свойства объекта во множестве $values.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

class ValueObject {
    private $value;
    public function __construct($value) {
        $this->value = $value;
    }
    
    public function getValue() {
        return $this->value;
    }
}

$c = 0;
CollectionFactory::generate(5, static function () use (& $c) {
        return new ValueObject($c++);
    })
    ->stream()
    ->filter(Predicates::whereIn('value', [0, 4, 9]))
    ->getCollection()
    ->toArray() // [#0, #4]
;

whereGreaterThan - Проверка свойства объекта на условие "больше"

[↑ Predicates Предикаты]

whereGreaterThan($property: string, $value: scalar): Closure; \\ <Fn($el: scalar): bool>

Метод инициирует функцию сравнения значения свойства объекта с $value.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

class ValueObject {
    private $value;
    public function __construct($value) {
        $this->value = $value;
    }
    
    public function getValue() {
        return $this->value;
    }
}

$c = 0;
CollectionFactory::generate(5, static function () use (& $c) {
        return new ValueObject($c++);
    })
    ->stream()
    ->filter(Predicates::whereGreaterThan('value', 3))
    ->getCollection()
    ->toArray() // [#4]
;

whereLessThan - Проверка свойства объекта на условие "меньше"

[↑ Predicates Предикаты]

whereLessThan($property: string, $value: scalar): Closure; \\ <Fn($el: scalar): bool>

Метод инициирует функцию сравнения значения свойства объекта с $value.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

class ValueObject {
    private $value;
    public function __construct($value) {
        $this->value = $value;
    }
    
    public function getValue() {
        return $this->value;
    }
}

$c = 0;
CollectionFactory::generate(5, static function () use (& $c) {
        return new ValueObject($c++);
    })
    ->stream()
    ->filter(Predicates::whereLessThan('value', 3))
    ->getCollection()
    ->toArray() // [#0, #1, #2]
;

whereGreaterOrEqual - Проверка свойства объекта на условие "больше либо равно"

[↑ Predicates Предикаты]

whereGreaterOrEqual($property: string, $value: scalar): Closure; \\ <Fn($el: scalar): bool>

Метод инициирует функцию сравнения значения свойства объекта с $value.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

class ValueObject {
    private $value;
    public function __construct($value) {
        $this->value = $value;
    }
    
    public function getValue() {
        return $this->value;
    }
}

$c = 0;
CollectionFactory::generate(5, static function () use (& $c) {
        return new ValueObject($c++);
    })
    ->stream()
    ->filter(Predicates::whereGreaterOrEqual('value', 3))
    ->getCollection()
    ->toArray() // [#3, #4]
;

whereLessOrEqual - Проверка свойства объекта на условие "меньше либо равно"

[↑ Predicates Предикаты]

whereLessOrEqual($property: string, $value: scalar): Closure; \\ <Fn($el: scalar): bool>

Метод инициирует функцию сравнения значения свойства объекта с $value.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;

class ValueObject {
    private $value;
    public function __construct($value) {
        $this->value = $value;
    }
    
    public function getValue() {
        return $this->value;
    }
}

$c = 0;
CollectionFactory::generate(5, static function () use (& $c) {
        return new ValueObject($c++);
    })
    ->stream()
    ->filter(Predicates::whereLessOrEqual('value', 3))
    ->getCollection()
    ->toArray() // [#1, #2, #3]
;

Comparators функции сравнения

[↑ Набор функций обхода и преобразования]

Группа конструкторов функций сравнения. Функции сравнения элементов необходимы при использовании методов сортировки, для того чтобы в правильном порядке расположить элементы. Итоговые функции сортировки имеют интерфейс <Fn($a: mixed, $b: mixed): int>, с логикой работы идентичной [https://www.php.net/manual/ru/function.usort].

scalarComparator - Сравнение скалярных значений

[↑ Comparators функции сравнения]

scalarComparator(): Closure; \\ <Fn($a: scalar, $b: scalar): int>

Метод инициирует функцию, которая сравнивает два значения. Функция сравнения возвращает целое, которое меньше, равно или больше нуля, если первый аргумент является соответственно меньшим, равным или большим, чем второй.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Comparators;

CollectionFactory::generate(5, static function (): int {
        return random_int(0, 10);
    })
    ->stream()
    ->sort(Comparators::scalarComparator())
    ->getCollection()
    ->toArray() // sorted value, for example [2, 3, 6, 7, 8]
;

objectPropertyComparator - Сравнение свойств объектов

[↑ Comparators функции сравнения]

objectPropertyComparator($property: string): Closure; \\ <Fn($a: object, $b: object): int>

Метод инициирует функцию, которая сравнивает два значения свойства объектов. Функция сравнения возвращает целое, которое меньше, равно или больше нуля, если первый аргумент является соответственно меньшим, равным или большим, чем второй.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Comparators;

class ValueObject {
    private $value;
    public function __construct($value) {
        $this->value = $value;
    }
    
    public function getValue() {
        return $this->value;
    }
}

CollectionFactory::generate(5, static function () {
        return new ValueObject(random_int(0, 10));
    })    
    ->stream()
    ->sort(Comparators::objectPropertyComparator('value'))
    ->getCollection()
    ->toArray() // sorted ValueObject objects, for example [#2, #3, #6, #7, #8]
;

callbackComparator - Определение функции для сравнения значений

[↑ Comparators функции сравнения]

callbackComparator($fun: <Fn($value: mixed): scalar>): Closure; \\ <Fn($a: mixed, $b: mixed): int>

Метод инициирует функцию, которая сравнивает два значения на основе их обработки функцией $fun. Функция сравнения возвращает целое, которое меньше, равно или больше нуля, если первый аргумент является соответственно меньшим, равным или большим, чем второй.

use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Comparators;

class ValueObject {
    private $value;
    public function __construct($value) {
        $this->value = $value;
    }
    
    public function getValue() {
        return $this->value;
    }
}

CollectionFactory::generate(5, static function () {
        return new ValueObject(random_int(0, 10));
    })    
    ->stream()
    ->sort(Comparators::callbackComparator(static function (ValueObject $valueObject) {
        return $valueObject->getValue();
    }))
    ->getCollection()
    ->toArray() // sorted ValueObject objects, for example [#2, #3, #6, #7, #8]
;

Converters Преобразователи элементов

[↑ Набор функций обхода и преобразования]

Группа конструктор функций для преобразования элементов. Результатом функции конвертера является <Fn($obj: mixed): mixed>.

toPropertyValue - Преобразование каждого элемента коллекции в значение свойства

[↑ Converters Преобразователи элементов]

toPropertyValue($property: string): Closure; \\ <Fn($obj: object): mixed>

Метод инициирует функцию, которая возвращает значение свойства объекта.

use WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Converters;

class ValueObject {
    private $value;
    public function __construct($value) {
        $this->value = $value;
    }
    
    public function getValue() {
        return $this->value;
    }
}

CollectionFactory::generate(5, static function (int $index): ValueObject {
        return new ValueObject($index);
    })
    ->stream()
    ->map(Converters::toPropertyValue('value'))
    ->getCollection()
    ->toArray() // [0, 1, 2, 3, 4 ]
;

toProperties - Преобразование каждого элемента коллекции в ассоциативный массив

[↑ Converters Преобразователи элементов]

toProperties($names: array<string>): Closure; \\ <Fn($obj: object): array>

Метод инициирует функцию, которая возвращает ассоциативный массив свойств объекта, ключи которого являются именами свойств.

use WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Converters;

class Person {
    private $name;
    private $surname;
    
    public function __construct(string $name, string $surname) 
    {
        $this->name = $name;
        $this->surname = $surname;
    }
    
    public function getName(): string 
    {
        return $this->name;
    }
    
    public function getSurname(): string
    {
        return $this->surname;
    }
}

CollectionFactory::generate(1, static function (int $index): Person {
        return new Person('Ivan', 'Ivanov');
    })
    ->stream()
    ->map(Converters::toProperties(['name', 'surname']))
    ->getCollection()
    ->toArray() // [['name' => 'Ivan', 'surname' => 'Ivanov']]
;

Reorganizers Преобразователи потоков

[↑ Набор функций обхода и преобразования]

Конструкторы методов преобразования потоков. В отличие от функций преобразования элементов, где каждому элементу исходной коллекции соответствует элемент новой коллекции с учетом позиции первого, методы преобразования потоков создают производную новую коллекцию с произвольным количеством элементов.

shuffle - Смена порядка следования элементов коллекции

[↑ Reorganizers Преобразователи потоков]

shuffle(): Closure; \\ <Fn(): Collection>

Метод инициирует функцию, которая возвращает новую коллекцию с измененным порядком следования элементов. Элементы будут следовать в случайном порядке.

use \WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Reorganizers;

CollectionFactory::numbers(5)
    ->stream()
    ->reorganize(Reorganizers::shuffle())
    ->getCollection()
    ->toArray() // for example [0, 3, 1, 2, 4]
;

random - Получение случайных элементов коллекции

[↑ Reorganizers Преобразователи потоков]

random($count = 1: int): Closure; \\ <Fn(): Collection>

Метод инициирует функцию, функция возвращает новую коллекцию которая содержит случайное ограниченное множество элементов исходной коллекции.

use \WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Reorganizers;

CollectionFactory::numbers(5)
    ->stream()
    ->reorganize(Reorganizers::random(2))
    ->getCollection()
    ->toArray() // for example [0, 3]
;

chunk - Разбиение на множество коллекций указанного размера

[↑ Reorganizers Преобразователи потоков]

chunk($size: int): Closure; \\ <Fn(): Collection>

Метод инициирует функцию, функция возвращает коллекцию коллекций количество элементов которых меньше либо равно $size.

use \WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Reorganizers;

CollectionFactory::numbers(10)
    ->stream()
    ->reorganize(Reorganizers::chunk(2))
    ->getCollection()
    ->toArray() // for example [[0, 1], [2, 3], ...]
;

collapse - Получение коллекции без дополнительных уровней вложенности

[↑ Reorganizers Преобразователи потоков]

collapse(): Closure; \\ <Fn(): Collection>

Метод инициирует функцию, функция возвращает коллекцию без вложенных контейнеров. Под контейнерами в данном контексте понимаются итерируемые структуры данных.

use \WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Reorganizers;

CollectionFactory::generate(3, static function (int $i): array {
        return [$i*2, $i*2 + 1];
    }) // [[0, 1], [2, 3], [4, 5]]
    ->stream()
    ->reorganize(Reorganizers::collapse())
    ->getCollection()
    ->toArray() // for example [0, 1, 2, 3, 4, 5]
;

Consumers Потребители

[↑ Набор функций обхода и преобразования]

Конструкторы функций потребителей. Содержит одну функцию распечатки значений элементов. В основном каждая функция потребитель разрабатывается индивидуально в исходном коде проекта.

dump - Распечатка значений элементов коллекции

[↑ Consumers - Потребители]

dump(): Closure; \\ <Fn(): Collection>

Метод инициирует функцию, которая распечатывает в поток вывода переданное значение.

use \WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Consumers;

CollectionFactory::numbers(5)
    ->stream()
    ->each(Consumers::dump()) // dumps each element of collection
;

Группировка и агрегация

[↑ Набор функций обхода и преобразования]

by

[↑ Группировка и агрегация]

$group = Group::by($fieldName): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;

$items = [
    ['name' => 'potato', 'type' => 'groceries', 'price' => 25],
    ['name' => 'milk', 'type' => 'groceries', 'price' => 50],
    ['name' => 'taxi', 'type' => 'transport', 'price' => 100],
    ['name' => 'taxi', 'type' => 'transport', 'price' => 70],
    ['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
    ['name' => 'cinema', 'type' => 'entertainment', 'price' => 20],
];

$result = CollectionFactory::from($items)
    ->stream()
    ->collect(Group::by('type'))
;
/* Result ->
[
    'groceries' => new \WS\Utils\Collections\ArrayList([
        ['name' => 'potato', 'type' => 'groceries', 'price' => 25],
        ['name' => 'milk', 'type' => 'groceries', 'price' => 50],
    ]),
    'transport' => new \WS\Utils\Collections\ArrayList([
       ['name' => 'taxi', 'type' => 'transport', 'price' => 100],
       ['name' => 'taxi', 'type' => 'transport', 'price' => 70],
   ]),
    'entertainment' => new \WS\Utils\Collections\ArrayList([
        ['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
        ['name' => 'cinema', 'type' => 'entertainment', 'price' => 20],
    ]),
];
*/

addToSet

[↑ Группировка и агрегация]

Group::addToSet($sourceKey, $destKey): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;

$items = [
    ['name' => 'potato', 'type' => 'groceries', 'price' => 25],
    ['name' => 'milk', 'type' => 'groceries', 'price' => 50],
    ['name' => 'taxi', 'type' => 'transport', 'price' => 100],
    ['name' => 'taxi', 'type' => 'transport', 'price' => 70],
    ['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
    ['name' => 'cinema', 'type' => 'entertainment', 'price' => 20],
];

$aggregation = Group::by('type')->addToSet('name', 'list');
$result = CollectionFactory::from($items)
    ->stream()
    ->collect($aggregation)
;
/* Result ->
[
    'groceries' => ['list' => ['potato', 'milk']],
    'transport' => ['list' => ['taxi']],
    'entertainment' => ['list' => ['cinema']],
];
*/

avg

[↑ Группировка и агрегация]

Group::avg($sourceKey, $destKey): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;

$items = [
    ['name' => 'potato', 'type' => 'groceries', 'price' => 30],
    ['name' => 'milk', 'type' => 'groceries', 'price' => 50],
    ['name' => 'taxi', 'type' => 'transport', 'price' => 100],
    ['name' => 'taxi', 'type' => 'transport', 'price' => 50],
    ['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
    ['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];

$aggregation = Group::by('type')->avg('price', 'avg');
$result = CollectionFactory::from($items)
    ->stream()
    ->collect($aggregation)
;
/* Result ->
[
    'groceries' => ['avg' => 40],
    'transport' => ['avg' => 75],
    'entertainment' => ['avg' => 30],
];
*/

count

[↑ Группировка и агрегация]

Group::count($destKey): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;

$items = [
    ['name' => 'potato', 'type' => 'groceries', 'price' => 30],
    ['name' => 'milk', 'type' => 'groceries', 'price' => 50],
    ['name' => 'tea', 'type' => 'groceries', 'price' => 50],
    ['name' => 'taxi', 'type' => 'transport', 'price' => 100],
    ['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
    ['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];

$aggregation = Group::by('type')->count('total');
$result = CollectionFactory::from($items)
    ->stream()
    ->collect($aggregation)
;
/* Result ->
[
    'groceries' => ['total' => 3],
    'transport' => ['total' => 1],
    'entertainment' => ['total' => 2],
];
*/

first

[↑ Группировка и агрегация]

Group::first($sourceKey, $destKey): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;

$items = [
    ['name' => 'potato', 'type' => 'groceries', 'price' => 30],
    ['name' => 'milk', 'type' => 'groceries', 'price' => 50],
    ['name' => 'taxi', 'type' => 'transport', 'price' => 100],
    ['name' => 'airplane', 'type' => 'transport', 'price' => 50],
    ['name' => 'Knicks game', 'type' => 'entertainment', 'price' => 300],
    ['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];

$aggregation = Group::by('type')->first('name', 'item');
$result = CollectionFactory::from($items)
    ->stream()
    ->collect($aggregation)
;
/* Result ->
[
    'groceries' => ['item' => 'potato'],
    'transport' => ['item' => 'taxi'],
    'entertainment' => ['item' => 'Knicks game'],
];
*/

last

[↑ Группировка и агрегация]

Group::last($sourceKey, $destKey): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;

$items = [
    ['name' => 'potato', 'type' => 'groceries', 'price' => 30],
    ['name' => 'milk', 'type' => 'groceries', 'price' => 50],
    ['name' => 'taxi', 'type' => 'transport', 'price' => 100],
    ['name' => 'airplane', 'type' => 'transport', 'price' => 50],
    ['name' => 'Knicks game', 'type' => 'entertainment', 'price' => 300],
    ['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];

$aggregation = Group::by('type')->last('name', 'item');
$result = CollectionFactory::from($items)
    ->stream()
    ->collect($aggregation)
;
/* Result ->
[
    'groceries' => ['item' => 'milk'],
    'transport' => ['item' => 'airplane'],
    'entertainment' => ['item' => 'cinema'],
];
*/

max

[↑ Группировка и агрегация]

Group::max($sourceKey, $destKey): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;

$items = [
    ['name' => 'potato', 'type' => 'groceries', 'price' => 30],
    ['name' => 'milk', 'type' => 'groceries', 'price' => 50],
    ['name' => 'taxi', 'type' => 'transport', 'price' => 100],
    ['name' => 'airplane', 'type' => 'transport', 'price' => 50],
    ['name' => 'Knicks game', 'type' => 'entertainment', 'price' => 300],
    ['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];

$aggregation = Group::by('type')->max('price', 'max');
$result = CollectionFactory::from($items)
    ->stream()
    ->collect($aggregation)
;
/* Result ->
[
    'groceries' => ['max' => 50],
    'transport' => ['max' => 100],
    'entertainment' => ['max' => 300],
];
*/

min

[↑ Группировка и агрегация]

Group::min($sourceKey, $destKey): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;

$items = [
    ['name' => 'potato', 'type' => 'groceries', 'price' => 30],
    ['name' => 'milk', 'type' => 'groceries', 'price' => 50],
    ['name' => 'taxi', 'type' => 'transport', 'price' => 100],
    ['name' => 'airplane', 'type' => 'transport', 'price' => 50],
    ['name' => 'Knicks game', 'type' => 'entertainment', 'price' => 300],
    ['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];

$aggregation = Group::by('type')->min('price', 'min');
$result = CollectionFactory::from($items)
    ->stream()
    ->collect($aggregation)
;
/* Result ->
[
    'groceries' => ['min' => 30],
    'transport' => ['min' => 50],
    'entertainment' => ['min' => 30],
];
*/

sum

[↑ Группировка и агрегация]

Group::sum($sourceKey, $destKey): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;

$items = [
    ['name' => 'potato', 'type' => 'groceries', 'price' => 30],
    ['name' => 'milk', 'type' => 'groceries', 'price' => 50],
    ['name' => 'taxi', 'type' => 'transport', 'price' => 100],
    ['name' => 'airplane', 'type' => 'transport', 'price' => 50],
    ['name' => 'Knicks game', 'type' => 'entertainment', 'price' => 300],
    ['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];

$aggregation = Group::by('type')->sum('price', 'spent');
$result = CollectionFactory::from($items)
    ->stream()
    ->collect($aggregation)
; 
/* Result ->
[
    'groceries' => ['spent' => 80],
    'transport' => ['spent' => 150],
    'entertainment' => ['spent' => 330],
];
*/

addAggregator

[↑ Группировка и агрегация]

Group::addAggregator($destKey, $callbackFn): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;
use \WS\Utils\Collections\Collection;

$items = [
    ['name' => 'potato', 'type' => 'groceries', 'price' => 30],
    ['name' => 'milk', 'type' => 'groceries', 'price' => 50],
    ['name' => 'taxi', 'type' => 'transport', 'price' => 100],
    ['name' => 'airplane', 'type' => 'transport', 'price' => 50],
    ['name' => 'Knicks game', 'type' => 'entertainment', 'price' => 300],
    ['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];

$aggregation = Group::by('type')->addAggregator('names', function (Collection $collection) { 
    $result = [];
    foreach ($collection as $item) {
        $result[] = $item['name'];
    }
    return implode(', ', $result);
});
$result = CollectionFactory::from($items)
    ->stream()
    ->collect($aggregation)
;
/* Result ->
[
    'groceries' => ['names' => 'potato, milk'],
    'transport' => ['names' => 'taxi, airplane'],
    'entertainment' => ['names' => 'Knicks game, cinema'],
];
*/

Все агрегаторы можно комбинировать между собой для получения желаемого результата.

use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;

$items = [
    ['name' => 'potato', 'type' => 'groceries', 'price' => 30],
    ['name' => 'milk', 'type' => 'groceries', 'price' => 50],
    ['name' => 'taxi', 'type' => 'transport', 'price' => 100],
    ['name' => 'airplane', 'type' => 'transport', 'price' => 50],
    ['name' => 'Knicks game', 'type' => 'entertainment', 'price' => 300],
    ['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];

$aggregation = Group::by('type')->avg('price', 'avg')->min('price', 'min')->max('price', 'max');
$result = CollectionFactory::from($items)
    ->stream()
    ->collect($aggregation)
;
/* Result ->
[
    'groceries' => ['avg' => 40, 'min' => 30, 'max' => 50],
    'transport' => ['avg' => 75, 'min' => 50, 'max' => 100],
    'entertainment' => ['avg' => 165, 'min' => 30, 'max' => 300],
];
*/