33[ ![ Test Suite] ( https://github.com/dakujem/toru/actions/workflows/php-test.yml/badge.svg )] ( https://github.com/dakujem/toru/actions/workflows/php-test.yml )
44[ ![ Coverage Status] ( https://coveralls.io/repos/github/dakujem/toru/badge.svg?branch=trunk )] ( https://coveralls.io/github/dakujem/toru?branch=trunk )
55
6- Toru is a standalone tool for _ iterable_ collections for simple day-to-day tasks and advanced optimizations.
6+ Toru is a standalone tool for _ iterable_ collections,
7+ ready for simple day-to-day tasks and advanced optimizations.
78Most of its functionality is based on native _ generators_ for efficiency with large data sets.
89
910>
1011> 💿 ` composer require dakujem/toru `
1112>
13+ > 📒 [ Changelog] ( changelog.md )
14+ >
1215
13- The package name comes from Japanese word "toru" (取る), which may mean "to take", "to pick up" or even "to collect".
14-
15- Toru provides a few common ** iteration primitives** (e.g. ` map ` , ` filter ` , ` tap ` ),
16- ** aggregates** (e.g. ` reduce ` , ` search ` , ` count ` )
17- and utility functions (e.g. ` chain ` ) implemented using generators.
18-
19- Also implements ** Lodash-style fluent call chaining** to simplify composition of various transformations on iterable collections.
20-
21- The aim of Toru is to provide simple tools to work with the native ` iterable ` type* .
22- Leveraging generators, Toru enables memory-efficient operations on large datasets.
16+ Toru provides a few common
17+ - ** iteration primitives** (e.g. ` map ` , ` filter ` , ` tap ` ),
18+ - ** aggregates** (e.g. ` reduce ` , ` search ` , ` count ` )
19+ - and utility functions (e.g. ` chain ` , ` valuesOnly ` , ` slice ` , ` limit ` )
2320
24- All callable parameters (_ mapper_ , _ predicate_ , _ reducer_ and _ effect_ functions)
25- always ** receive keys** along with values.
26- This is a key advantage over native functions like ` array_map ` , ` array_reduce ` , ` array_walk ` , or ` array_filter ` .
21+ ... implemented using ** generators** .
2722
28- Use Toru when :
23+ TL;DR :
2924
30- - in need to perform operations on ` iterable ` without converting to arrays
31- - in need to work with _ keys _ , as alternative to ` array_map ` , ` array_filter ` or ` array_reduce `
32- - unable to use ` foreach `
33- - working with large datasets
34- - running out of memory when transforming large collections (using arrays)
35- - wanting to compose collection transformations neatly in fluent call chain, Lodash-style
36- - in need of lazy evaluation (on-demand, per-element)
25+ - transform elements of native ` iterable ` type * collections (iterators and arrays) _ without _ converting to arrays
26+ - keys (indexes) provided for every mapper, filter, reducer or effect function
27+ - fluent call chaining enabled (Lodash-style)
28+ - lazy per-element evaluation of transformations
29+ - transform large data sets without increasing memory usage
30+ - better memory efficiency of generators compared to native array functions
31+ - slower than native array functions or direct transformations inside a ` foreach ` block
3732
3833>
3934> \* The ` iterable ` is a built-in compile time type alias for ` array|Traversable ` encompassing all arrays and iterators,
4035> so it's not exactly a native type, technically speaking.
4136>
4237
38+ ** Fluent call chaining** enables neat transformation composition.
39+ ``` php
40+ _dash($collection)
41+ ->filter(predicate: $filterFunction)
42+ ->map(values: $mapperFunction)
43+ ->chain($moreElements)
44+ ->valuesOnly();
45+ ```
46+
47+ Toru enables ** memory-efficient operations** on large data sets,
48+ because it leverages generators, which work on per-element basis and do not allocate extra memory.
49+ ``` php
50+ // no extra memory wasted on creating a filtered array
51+ $filtered = Itera::filter(input: $hugeDataSet, predicate: $filterFunction);
52+ foreach($filtered as $key => $value){ /* ... */ }
53+ ```
54+
55+ All callable parameters always ** receive keys** along with values.
56+ This is a key advantage over native functions like ` array_map ` , ` array_reduce ` , ` array_walk ` , or ` array_filter ` .
57+ ``` php
58+ $addresses = [
59+ 'john.doe@example.com' => 'John Doe',
60+ 'jane.doe@example.com' => 'Jane Doe',
61+ ];
62+ $recipients = Itera::map(
63+ $addresses,
64+ fn($recipientName, $recipientAddress) => new Recipient($recipientAddress, $recipientName),
65+ );
66+ Mailer::send($mail, $recipients);
67+ ```
68+
69+ > 🥋
70+ > The package name comes from Japanese word "toru" (取る), which may mean "to take", "to pick up" or even "to collect".
71+
4372
4473## Examples
4574
@@ -99,7 +128,7 @@ Most of the primitives described in API section below are implemented in **3 for
99128
100129Example of _ filtering_ and _ mapping_ a collection, then _ appending_ some more already processed elements.
101130
102- Usage of the individual static methods example :
131+ Usage of the individual ** static methods** :
103132``` php
104133use Dakujem\Toru\Itera;
105134
@@ -109,7 +138,18 @@ $merged = Itera::chain($mapped, $moreElements);
109138$processed = Itera::valuesOnly(input: $merged);
110139```
111140
112- Usage of the partially applied methods example:
141+ Usage of the ` Dash ` wrapper for fluent ** call chaining** :
142+ ``` php
143+ use Dakujem\Toru\Dash;
144+
145+ $processed = Dash::collect($collection)
146+ ->filter(predicate: $filterFunction)
147+ ->apply(values: $mapperFunction)
148+ ->chain($moreElements)
149+ ->valuesOnly();
150+ ```
151+
152+ Usage of the ** partially applied methods** :
113153``` php
114154use Dakujem\Toru\Pipeline;
115155use Dakujem\Toru\IteraFn;
@@ -123,20 +163,10 @@ $processed = Pipeline::through(
123163);
124164```
125165
126- Usage of the ` Dash ` fluent wrapper example:
127- ``` php
128- use Dakujem\Toru\Dash;
129-
130- $processed = Dash::collect($collection)
131- ->filter(predicate: $filterFunction)
132- ->apply(values: $mapperFunction)
133- ->chain($moreElements)
134- ->valuesOnly();
135- ```
136-
137- The ` $processed ` collection can now be iterated over. All the above operations are applied at this point.
166+ The ` $processed ` collection can now be iterated over.
167+ All the above operations are applied at this point only, on per-element basis.
138168``` php
139- foreach($processed as $value){
169+ foreach ($processed as $value) {
140170 // The filtered and mapped values from $collection will appear here,
141171 // followed by the elements present in $moreElements.
142172}
@@ -1006,19 +1036,21 @@ You might not need this library.
10061036- ` mpetrovich/dash ` provides a full range of transformation functions, uses _ arrays_ internally
10071037- ` lodash-php/lodash-php ` imitates Lodash and provides a full range of utilities, uses _ arrays_ internally
10081038- ` nikic/iter ` implements a range of iteration primitives using _ generators_ , authored by a PHP core team member
1009- - ` illuminate/collections ` should cover the needs of most Laravel developers, check the inner implementation for details
1010- - in many cases, a ` foreach ` will do the same job
1039+ - ` illuminate/collections ` should cover the needs of most Laravel developers, but uses _ arrays _ internally
1040+ - in many cases, a ` foreach ` will do the job
10111041
1012- This library (` dakujem/toru ` ) does not provide a full range of ready-made transformation functions,
1013- rather provides the most common ones and means to bring in and compose own transformations.
1042+ Toru library (` dakujem/toru ` ) does not provide a full range of ready-made transformation functions,
1043+ rather provides the most common ones and means to bring in and compose own transformations.
1044+ It works well with and along with the aforementioned and other such libraries.
10141045
1015- It originally started as an alternative to ` nikic/iter ` for daily tasks, which to me has a somewhat cumbersome interface.
1046+ Toru originally started as an alternative to ` nikic/iter ` for daily tasks,
1047+ which to me has a somewhat cumbersome interface.
10161048The ` Itera ` static _ class_ tries to fix that
10171049by using a single class import instead of multiple function imports
10181050and by reordering the parameters so that the input collection is consistently the first one.
1019- Still, composing multiple operations into one transformation is cumbersome, so the ` IteraFn ` factory was implemented to fix that.
1020- It worked well, but was still verbose for mundane tasks.
1021- To allow concise fluent/chained calls (like with Lodash), the ` Dash ` class was designed.
1051+ Still, composing multiple operations into one transformation felt cumbersome, so the ` IteraFn ` factory was implemented to fix that.
1052+ It worked well, but was still kind of verbose for mundane tasks.
1053+ To allow concise fluent/chained calls (like with Lodash), the ` Dash ` class was then designed.
10221054With it, it's possible to compose transformations neatly.
10231055
10241056
@@ -1031,7 +1063,8 @@ That being said, good quality PRs will be accepted.
10311063Possible additions may include:
10321064
10331065- ` combine ` values and keys
1034- - ` zip ` multiple iterables
1066+ - ` zip ` multiple iterables (python, haskell, etc.)
1067+ - ` alternate ` multiple iterables (load-balance elements, mix)
10351068
10361069
10371070---
0 commit comments