Инструменты итератора, или сокращенно itertools , представляют собой набор удобных инструментов для обработки последовательностей данных, таких как массивы, итераторы и строки. Некоторые имена и API основаны на Python itertools .
Примеры
Общие операции включают в себя:
map
и mapBy
filter
, difference
sorted
groupBy
accumulate
, collapse
и reduce
Чтобы использовать доступные фильтры/функции itertools через Twig, просто добавьте это определение службы в свой config/services.yaml
Zicht itertools twigExtension :
tags : ['twig.extension']
composer test
composer lint
В приведенных ниже примерах будут использоваться следующие данные, чтобы проиллюстрировать, как работают различные инструменты Iterator:
$ 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 ,
],
];
Используя приведенный выше пример данных, вы можете использовать itertools , чтобы получить все уникальные цвета автомобилей в алфавитном порядке:
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'}
Вы можете добиться того же в 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 %}
Многим itertools можно передать параметр $strategy
. Этот параметр используется для получения значения из элементов коллекции. $strategy
может быть одним из трех:
null, и в этом случае возвращается сам элемент. Например:
use function Zicht itertools iterable ;
$ result = iterable ( $ words )-> map ( null );
var_dump ( $ result );
// {0: 'Useful', 1: 'Goonies', 2: 'oven', 3: 'Bland', 4: 'notorious'}
Или в Twig:
{{ dump ( word |it. map ) }}
замыкание, и в этом случае замыкание вызывается со значением элемента и ключом в качестве параметров, которые будут использоваться для вычисления возвращаемого значения. Например:
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}
Или в Twig:
{{ dump ( numbers |it. map ( num => 2 * num )) }}
строка, и в этом случае эта строка используется для создания замыкания, которое пытается найти общедоступные свойства, методы или индексы массива. Например:
use function Zicht itertools iterable ;
$ result = iterable ( $ vehicles )-> map ( ' type ' );
var_dump ( $ result );
// {0: 'car', 1: 'bike', 2: 'unicicle', 3: 'car'}
Или в Twig:
{{ dump ( word |it. map ) }}
Строка может состоять из нескольких слов, разделенных точками, что обеспечивает доступ к вложенным свойствам, методам и индексам массива.
Если одно из слов в строке невозможно преобразовать в существующее свойство, метод или индекс массива, будет возвращено значение null
. Например:
use function Zicht itertools iterable ;
$ result = iterable ( $ vehicles )-> map ( ' colors.2 ' );
var_dump ( $ result );
// {0: 'blue', 1: 'blue', 2: null, 3: null}
Или в Twig:
{{ dump ( vehicles |it. map ( ' colors.2 ' )) }}
Один из способов использования инструментов Iterator — преобразовать массив, Iterator, строку и т. д. в IterableIterator
. Этот класс обеспечивает удобный интерфейс для всех распространенных операций. Например:
use function Zicht itertools iterable ;
$ result = iterable ( $ vehicles )-> filter ( ' is_cool ' )-> mapBy ( ' id ' )-> map ( ' type ' );
var_dump ( $ result );
// {5: 'unicicle', 9: 'car'}
Или в Twig:
{{ dump ( vehicles |it. filter ( ' is_cool ' ).mapBy( ' id ' ).map( ' type ' )) }}
Сопоставление преобразует одну коллекцию в другую коллекцию равной длины. Использование map
позволяет манипулировать элементами, а mapBy
позволяет манипулировать ключами коллекции.
Например, мы можем использовать замыкание для создания заголовка для каждого элемента в $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'}
Используя стратегию получения строк, мы можем легко получить типы для каждого элемента в $vehicles
сопоставленные с идентификаторами транспортных средств. Например:
use function Zicht itertools iterable ;
$ types = iterable ( $ vehicles )-> mapBy ( ' id ' )-> map ( ' type ' );
var_dump ( $ types );
// {1: 'car', 2: 'bike', 5: 'unicicle', 9: 'car'}
Или в Twig:
{{ dump ( vehicles |it. mapBy ( ' id ' ).map( ' type ' )) }}
В Mappings.php доступно несколько распространенных замыканий сопоставления. Вызов этих функций возвращает замыкание, которое можно передать в map
и mapBy
. Например:
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}
Или в Twig:
{{ dump ( words |it. map ( it . mappings . length )) }}
Фильтрация преобразует одну коллекцию в другую, возможно более короткую. С помощью filter
оценивается каждый элемент в коллекции, элементы, которые считаются empty
будут отклонены, а элементы, которые не являются empty
будут пропущены через фильтр.
Например, мы можем использовать замыкание, чтобы определить, является ли элемент дорогим, тогда filter
будет пропускать только дорогие элементы:
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'}
Или в Twig:
{{ dump ( vehicles |it. filter ( vehicle => vehicle . price >= 10000 ).map( ' type ' )) }}
Используя стратегию получения строк, мы можем получить только те $vehicles
, которые считаются крутыми. Например:
use function Zicht itertools iterable ;
$ coolVehicleTypes = iterable ( $ vehicles )-> filter ( ' is_cool ' )-> map ( ' type ' );
var_dump ( $ coolVehicleTypes );
// {5: 'unicicle', 9: 'car'}
Или в Twig:
{{ dump ( vehicles |it. filter ( ' is_cool ' ).map( ' type ' )) }}
В filter.php доступно несколько распространенных замыканий фильтров. Вызов этой функции возвращает замыкание, которое можно передать в filter
. Например:
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'}
Или в Twig:
{{ dump ( words |it. filter ( it . filters . in ([ ' Shining ' , " My little pony', 'Goonies'])) }}
sorted
преобразует одну коллекцию в другую коллекцию равного размера, но с возможным переупорядочением элементов.
Например, используя стратегию получения null
значений, которая используется по умолчанию, мы будем сортировать значения элементов в порядке возрастания:
use function Zicht itertools iterable ;
$ ordered = iterable ( $ numbers )-> sorted ();
var_dump ( $ ordered );
// {0: 1, 2: 2, 1: 3, 4: 4, 3: 5}
Или в Twig:
{{ dump ( numbers |it. sorted }}
Алгоритм сортировки сохранит ключи и гарантированно будет стабильным. Т.е. когда элементы сортируются по одному и тому же значению, порядок сортировки гарантированно совпадает с порядком входных элементов. Это противоречит стандартным функциям сортировки PHP.
Используя стратегию получения замыкания, возвращаемое значение используется для определения порядка. Замыкание вызывается ровно один раз для каждого элемента, и полученные значения должны быть сопоставимы. Например:
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'};
Mappings.php предоставляет замыкание сопоставления, которое возвращает случайное число. Это можно использовать для сортировки коллекции в случайном порядке. Например:
use Zicht itertools util Mappings ;
use function Zicht itertools iterable ;
$ randomized = iterable ( $ words )-> sorted (Mappings:: random ());
var_dump ( $ randomized );
// {... randomly ordere words ...}
Или в Twig:
{{ dump ( words |it. sorted ( it . mappings . random )) }}
groupBy
преобразует одну коллекцию в одну или несколько коллекций, которые группируют элементы по определенному критерию.
Например, используя стратегию получения строк, мы можем сгруппировать все $vehicles
одного типа вместе:
use function Zicht itertools iterable ;
$ vehiclesByType = iterable ( $ vehicles )-> groupBy ( ' type ' );
var_dump ( $ vehiclesByType );
// {'bike': {1: [...]}, 'car': {0: [...], 3: [...]} 'unicicle': {2: [...]}}
Или в Twig:
{{ dump ( vehicles |it. groupBy ( ' type ' )) }}
Это не значит, что исходные ключи от транспортных средств по-прежнему являются частью результирующих групп, а элементы внутри каждой группы сохраняют порядок, который они имели во входных данных, то есть используется стабильная сортировка, предоставляемая sorted
.
reduce
преобразует коллекцию в одно значение, вызывая замыкание двух аргументов кумулятивно для элементов коллекции, слева направо.
Например, без каких-либо аргументов reduce
добавит все элементы коллекции вместе:
use function Zicht itertools iterable ;
$ sum = iterable ( $ numbers )-> reduce ();
var_dump ( $ sum );
// 15
Или в Twig:
{{ dump ( numbers |it. reduce ) }}
В приведенном выше примере используемое замыкание по умолчанию выглядит следующим образом:
public static function add ( $ a , $ b ): Closure
{
return $ a + $ b ;
}
Учитывая, что $numbers
состоит из элементов {1, 3, 2, 5, 4}, замыкание add
вызывается четыре раза:
$ sum = Reductions:: add (Reductions:: add (Reductions:: add (Reductions:: add (( 1 , 3 ), 2 ), 5 ), 4 ));
var_dump ( $ sum );
// 15
В Reduction.php доступно несколько распространенных замыканий сокращения. Вызов этих функций возвращает замыкание, которое можно передать в reduction
. Например:
use Zicht itertools util Reductions ;
use function Zicht itertools iterable ;
$ scentence = iterable ( $ words )-> reduce (Reductions:: join ( ' - ' ));
var_dump ( $ scentence );
// 'Useful - Goonies - oven - Bland - notorious'
Или в Twig:
{{ dump ( words |it. reduce ( it . reductions . join ( ' - ' )) }}
Еще одно распространенное сокращение — объединение нескольких списков в один список. Мы называем этот процесс коллапсом. Этот процесс также может быть достигнут с помощью reduce
и объединения в chain
, однако, поскольку он используется часто, помощник collapse
упрощает его использование, например:
use function Zicht itertools iterable ;
$ flat = iterable ([[ ' one ' , ' two ' ], [ ' three ' ]])-> collapse ();
var_dump ( $ flat );
// {0: 'one', 1: 'two', 0: 'three'}
Или в Twig:
{% set data = [[ ' one ' , ' two ' ], [ ' three ' ]] %}
{{ dump ( data |it. collapse ) }}