zicht/itertools
最新稳定版本:3.0.3
Composer 安装命令:
composer require zicht/itertools
包简介
A collection of functions that mirror the Python itertools library
README 文档
README
Zicht Iterator Tools Library
The Iterator Tools, or itertools for short, are a collection of convenience tools to handle sequences of data such as arrays, iterators, and strings. Some of the naming and API is based on the Python itertools.
Common operations include:
- mapping:
mapandmapBy - filtering:
filter,difference - sorting:
sorted - grouping:
groupBy - reducing:
accumulate,collapse, andreduce
Usage
In order to use the available itertools filters/functions via Twig, simply add this service definition in your config/services.yaml
Zicht\Itertools\twig\Extension: tags: ['twig.extension']
Scripts
- unit test:
composer test - lint test:
composer lint
Example data
The examples below will use the following data to illustrate how various Iterator tools work:
$words = ['Useful', 'Goonies', 'oven', 'Bland', 'notorious']; $numbers = [1, 3, 2, 5, 4]; $vehicles = [ [ 'id' => 1, 'type' => 'car', 'wheels' => 4, 'colors' => ['red', 'green', 'blue'], 'is_cool' => false, 'price' => 20000, ], [ 'id' => 2, 'type' => 'bike', 'wheels' => 2, 'colors' => ['red', 'green', 'blue'], 'is_cool' => false, 'price' => 600, ], [ 'id' => 5, 'type' => 'unicicle', 'wheels' => 1, 'colors' => ['red'], 'is_cool' => true, 'price' => 150, ], [ 'id' => 9, 'type' => 'car', 'wheels' => 8, 'colors' => ['blue'], 'is_cool' => true, 'price' => 100000, ], ];
Examples
With the example data above, this is how you could use itertools to get all unique colors of the cars in alphabetical order:
use Zicht\Itertools\util\Filters; use function Zicht\Itertools\iterable; $vehicles = iterable($vehicles) ->filter(Filters::equals('car', 'type')) // {[vehicle...], [vehicle...]} ->map('colors') // {0: ['red', 'green', 'blue'], 1: ['blue']} ->collapse() // {0: 'red', 1: 'green', 2: 'blue', 3: 'blue'} ->unique() // {0: 'red', 1: 'green', 2: 'blue'} ->sorted(); // {2: 'blue', 1: 'green', 0: 'red'}
You can achieve the same in Twig:
{% for vehicle_color in vehicles
|it.filter(it.filters.equals('car', 'type'))
|it.map('colors')
|it.collapse
|it.unique
|it.sorted
%}
{{ vehicle_color }}
{% endfor %}
Getter strategy
Many itertools can be passed a $strategy parameter. This parameter
is used to obtain a value from the elements in the collection. The
$strategy can be one of three things:
-
null, in which case the element itself is returned. For example:
use function Zicht\Itertools\iterable; $result = iterable($words)->map(null); var_dump($result); // {0: 'Useful', 1: 'Goonies', 2: 'oven', 3: 'Bland', 4: 'notorious'}
Or in Twig:
{{ dump(word|it.map) }} -
a closure, in which case the closure is called with the element value and key as parameters to be used to compute a return value. For example:
use function Zicht\Itertools\iterable; $getDouble = fn($value, $key) => 2 * $value; $result = iterable($numbers)->map($getDouble); var_dump($result); // {0: 2, 1: 6, 2: 4, 3: 10, 4: 8}
Or in Twig:
{{ dump(numbers|it.map(num => 2 * num)) }} -
a string, in which case this string is used to create a closure that tries to find public properties, methods, or array indexes. For example:
use function Zicht\Itertools\iterable; $result = iterable($vehicles)->map('type'); var_dump($result); // {0: 'car', 1: 'bike', 2: 'unicicle', 3: 'car'}
Or in Twig:
{{ dump(word|it.map) }}The string can consist of multiple dot separated words, allowing access to nested properties, methods, and array indexes.
If one of the words in the string can not be resolved into an existing property, method, or array index, the value
nullwill be returned. For example:use function Zicht\Itertools\iterable; $result = iterable($vehicles)->map('colors.2'); var_dump($result); // {0: 'blue', 1: 'blue', 2: null, 3: null}
Or in Twig:
{{ dump(vehicles|it.map('colors.2')) }}
Fluent interface
One way to use the Iterator Tools is to convert the array, Iterator,
string, etc into an IterableIterator. This class provides a fluent
interface to all of the common operations. For example:
use function Zicht\Itertools\iterable; $result = iterable($vehicles)->filter('is_cool')->mapBy('id')->map('type'); var_dump($result); // {5: 'unicicle', 9: 'car'}
Or in Twig:
{{ dump(vehicles|it.filter('is_cool').mapBy('id').map('type')) }}
Mapping
Mapping converts one collection into another collection of equal
length. Using map allows manipulation of the elements while mapBy
allows manipulation of the collection keys.
For example, we can use a closure to create a title for each element
in $vehicles:
use function Zicht\Itertools\iterable; $getTitle = fn($value, $key) => sprintf('%s with %s wheels', $value['type'], $value['wheels']); $titles = iterable($vehicles)->map($getTitle); var_dump($titles); // {0: 'car with 4 wheels', ..., 3: 'car with 8 wheels'}
Using the string getter strategy we can easily get
the types for each element in $vehicles mapped by the vehicle
identifiers. For example:
use function Zicht\Itertools\iterable; $types = iterable($vehicles)->mapBy('id')->map('type'); var_dump($types); // {1: 'car', 2: 'bike', 5: 'unicicle', 9: 'car'}
Or in Twig:
{{ dump(vehicles|it.mapBy('id').map('type')) }}
There are several common mapping closures available
in mappings.php. Calling these
functions returns a closure that can be passed to map and mapBy.
For example:
use Zicht\Itertools\util\Mappings; use function Zicht\Itertools\iterable; $lengths = iterable($words)->map(Mappings::length()); var_dump($lengths); // {0: 6, 1: 3, 2: 4, 3: 5, 4: 9}
Or in Twig:
{{ dump(words|it.map(it.mappings.length)) }}
Filtering
Filtering converts one collection into another, possibly shorter,
collection. Using filter each element in the collection is
evaluated, the elements that are considered empty will be rejected,
while the elements that are not empty will be allowd to pass through
the filter.
For example, we can use a closure to determine if an element is
expensive, the filter will then only allow the expensive elements
through:
use function Zicht\Itertools\iterable; $isExpensive = fn($value, $key) => $value['price'] >= 10000; $expensiveTypes = iterable($vehicles)->filter($isExpensive)->map('type'); var_dump($expensiveTypes); // {1: 'car', 9: 'car'}
Or in Twig:
{{ dump(vehicles|it.filter(vehicle => vehicle.price >= 10000).map('type')) }}
Using the string getter strategy we can get only
the $vehicles that are considered to be cool. For example:
use function Zicht\Itertools\iterable; $coolVehicleTypes = iterable($vehicles)->filter('is_cool')->map('type'); var_dump($coolVehicleTypes); // {5: 'unicicle', 9: 'car'}
Or in Twig:
{{ dump(vehicles|it.filter('is_cool').map('type')) }}
There are several common filter closures available
in filters.php. Calling these
function returns a closure that can be passed to filter. For
example:
use Zicht\Itertools\util\Filters; use function Zicht\Itertools\iterable; $movieWords = iterable($words)->filter(Filters::in(['Shining', 'My little pony', 'Goonies'])); var_dump($movieWords); // {1: 'Goonies'}
Or in Twig:
{{ dump(words|it.filter(it.filters.in(['Shining', "My little pony', 'Goonies'])) }}
Sorting
sorted converts one collection into another collection of equal size
but with the elements possibly reordered.
For example, using the null getter strategy,
which is the default, we will sort using the element values in
ascending order:
use function Zicht\Itertools\iterable; $ordered = iterable($numbers)->sorted(); var_dump($ordered); // {0: 1, 2: 2, 1: 3, 4: 4, 3: 5}
Or in Twig:
{{ dump(numbers|it.sorted }}
The sorting algorithm will preserve the keys and is guaranteed to be stable. I.e. when elements are sorted using the same value, then the sorted order is guaranteed to be the same as the order of the input elements. This is contrary to the standard PHP sorting functions.
Using the closure getter strategy the returned value is used to determine the order. The closure is called exactly once per element, and the resulting values must be comparable. For example:
use function Zicht\Itertools\iterable; $getLower = fn($value, $key) => strtolower($value); $ordered = iterable($words)->sorted($getLower); var_dump($ordered); // {3: 'Bland', 1: 'Goonies', 2: 'oven', 0: 'Useful', 4: 'notorious'};
The mappings.php provides a mapping closure which returns a random number. This can be used to sort a collection in a random order. For example:
use Zicht\Itertools\util\Mappings; use function Zicht\Itertools\iterable; $randomized = iterable($words)->sorted(Mappings::random()); var_dump($randomized); // {... randomly ordere words ...}
Or in Twig:
{{ dump(words|it.sorted(it.mappings.random)) }}
Grouping
groupBy converts one collection into one or more collections that
group the elements together on a specific criteria.
For example, using the string getter strategy we
can group all the $vehicles of the same type together:
use function Zicht\Itertools\iterable; $vehiclesByType = iterable($vehicles)->groupBy('type'); var_dump($vehiclesByType); // {'bike': {1: [...]}, 'car': {0: [...], 3: [...]} 'unicicle': {2: [...]}}
Or in Twig:
{{ dump(vehicles|it.groupBy('type')) }}
Not that the original keys of the vehicles are still part of the
resulting groups, and the elements within each group keep the order
that they had in the input, i.e. it uses the stable sorting provided
by sorted.
Reducing
reduce converts a collection into a single value by calling a
closure of two arguments cumulatively to the elements in the
collection, from left to right.
For example, without any arguments reduce will add all elements of
the collection together:
use function Zicht\Itertools\iterable; $sum = iterable($numbers)->reduce(); var_dump($sum); // 15
Or in Twig:
{{ dump(numbers|it.reduce) }}
In the above example, the default closure that is used looks like this:
public static function add($a, $b): \Closure { return $a + $b; }
Given that $numbers consists of the elements {1, 3, 2, 5, 4}, the
add closure is called four times:
$sum = Reductions::add(Reductions::add(Reductions::add(Reductions::add((1, 3), 2), 5), 4)); var_dump($sum); // 15
There are several common reduction closures available
in reductions.php. Calling
these functions returns a closure that can be passed to reduction.
For example:
use Zicht\Itertools\util\Reductions; use function Zicht\Itertools\iterable; $scentence = iterable($words)->reduce(Reductions::join(' - ')); var_dump($scentence); // 'Useful - Goonies - oven - Bland - notorious'
Or in Twig:
{{ dump(words|it.reduce(it.reductions.join(' - ')) }}
Another common reduction is chaining multiple lists together into one list.
We call this process collapse. This process can also be achieved using reduce
and chain together, however, because it is used frequently the collapse helper
makes its usage easier, for example:
use function Zicht\Itertools\iterable; $flat = iterable([['one', 'two'], ['three']])->collapse(); var_dump($flat); // {0: 'one', 1: 'two', 0: 'three'}
Or in Twig:
{% set data = [['one', 'two'], ['three']] %}
{{ dump(data|it.collapse) }}
Maintainer(s)
- Boudewijn Schoon boudewijn@zicht.nl
- Virginia Meijer virginia@zicht.nl
zicht/itertools 适用场景与选型建议
zicht/itertools 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 27.64k 次下载、GitHub Stars 达 10, 最近一次更新时间为 2016 年 12 月 19 日, 在 PHP 生态内属于活跃度较高的组件。
我们在过去多个企业项目中使用过 zicht/itertools 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 zicht/itertools 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
统计信息
- 总下载量: 27.64k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 11
- 点击次数: 7
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2016-12-19