As ferramentas iteradoras, ou itertools , são uma coleção de ferramentas convenientes para lidar com sequências de dados, como arrays, iteradores e strings. Parte da nomenclatura e da API são baseadas nas itertools do Python.
Exemplos
As operações comuns incluem:
map
e mapBy
filter
, difference
sorted
groupBy
accumulate
, collapse
e reduce
Para usar os filtros/funções itertools disponíveis via Twig, basta adicionar esta definição de serviço em seu config/services.yaml
Zicht itertools twigExtension :
tags : ['twig.extension']
composer test
composer lint
Os exemplos abaixo usarão os seguintes dados para ilustrar como funcionam várias ferramentas do Iterador:
$ 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 ,
],
];
Com os dados de exemplo acima, é assim que você poderia usar itertools para obter todas as cores exclusivas dos carros em ordem alfabética:
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'}
Você pode conseguir o mesmo no 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 %}
Muitas itertools podem receber um parâmetro $strategy
. Este parâmetro é usado para obter um valor dos elementos da coleção. A $strategy
pode ser uma de três coisas:
null, caso em que o próprio elemento é retornado. Por exemplo:
use function Zicht itertools iterable ;
$ result = iterable ( $ words )-> map ( null );
var_dump ( $ result );
// {0: 'Useful', 1: 'Goonies', 2: 'oven', 3: 'Bland', 4: 'notorious'}
Ou em Twig:
{{ dump ( word |it. map ) }}
um encerramento, caso em que o encerramento é chamado com o valor do elemento e a chave como parâmetros a serem usados para calcular um valor de retorno. Por exemplo:
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}
Ou em Twig:
{{ dump ( numbers |it. map ( num => 2 * num )) }}
uma string, caso em que esta string é usada para criar um fechamento que tenta encontrar propriedades públicas, métodos ou índices de array. Por exemplo:
use function Zicht itertools iterable ;
$ result = iterable ( $ vehicles )-> map ( ' type ' );
var_dump ( $ result );
// {0: 'car', 1: 'bike', 2: 'unicicle', 3: 'car'}
Ou em Twig:
{{ dump ( word |it. map ) }}
A string pode consistir em várias palavras separadas por pontos, permitindo acesso a propriedades, métodos e índices de array aninhados.
Se uma das palavras na string não puder ser resolvida em uma propriedade, método ou índice de matriz existente, o valor null
será retornado. Por exemplo:
use function Zicht itertools iterable ;
$ result = iterable ( $ vehicles )-> map ( ' colors.2 ' );
var_dump ( $ result );
// {0: 'blue', 1: 'blue', 2: null, 3: null}
Ou em Twig:
{{ dump ( vehicles |it. map ( ' colors.2 ' )) }}
Uma maneira de usar as ferramentas Iterator é converter o array, Iterator, string, etc. em um IterableIterator
. Esta classe fornece uma interface fluente para todas as operações comuns. Por exemplo:
use function Zicht itertools iterable ;
$ result = iterable ( $ vehicles )-> filter ( ' is_cool ' )-> mapBy ( ' id ' )-> map ( ' type ' );
var_dump ( $ result );
// {5: 'unicicle', 9: 'car'}
Ou em Twig:
{{ dump ( vehicles |it. filter ( ' is_cool ' ).mapBy( ' id ' ).map( ' type ' )) }}
O mapeamento converte uma coleção em outra coleção de igual comprimento. Usar map
permite a manipulação dos elementos enquanto mapBy
permite a manipulação das chaves da coleção.
Por exemplo, podemos usar um encerramento para criar um título para cada elemento em $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'}
Usando a estratégia string getter, podemos facilmente obter os tipos de cada elemento em $vehicles
mapeados pelos identificadores de veículo. Por exemplo:
use function Zicht itertools iterable ;
$ types = iterable ( $ vehicles )-> mapBy ( ' id ' )-> map ( ' type ' );
var_dump ( $ types );
// {1: 'car', 2: 'bike', 5: 'unicicle', 9: 'car'}
Ou em Twig:
{{ dump ( vehicles |it. mapBy ( ' id ' ).map( ' type ' )) }}
Existem vários fechamentos de mapeamento comuns disponíveis em mapeamentos.php. Chamar essas funções retorna um encerramento que pode ser passado para map
e mapBy
. Por exemplo:
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}
Ou em Twig:
{{ dump ( words |it. map ( it . mappings . length )) }}
A filtragem converte uma coleção em outra coleção, possivelmente mais curta. Usando filter
cada elemento da coleção é avaliado, os elementos considerados empty
serão rejeitados, enquanto os elementos que não estiverem empty
poderão passar pelo filtro.
Por exemplo, podemos usar um fechamento para determinar se um elemento é caro, o filter
permitirá apenas a passagem dos elementos caros:
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'}
Ou em Twig:
{{ dump ( vehicles |it. filter ( vehicle => vehicle . price >= 10000 ).map( ' type ' )) }}
Usando a estratégia string getter, podemos obter apenas os $vehicles
que são considerados legais. Por exemplo:
use function Zicht itertools iterable ;
$ coolVehicleTypes = iterable ( $ vehicles )-> filter ( ' is_cool ' )-> map ( ' type ' );
var_dump ( $ coolVehicleTypes );
// {5: 'unicicle', 9: 'car'}
Ou em Twig:
{{ dump ( vehicles |it. filter ( ' is_cool ' ).map( ' type ' )) }}
Existem vários fechamentos de filtros comuns disponíveis em filter.php. Chamar essas funções retorna um encerramento que pode ser passado para filter
. Por exemplo:
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'}
Ou em Twig:
{{ dump ( words |it. filter ( it . filters . in ([ ' Shining ' , " My little pony', 'Goonies'])) }}
sorted
converte uma coleção em outra coleção de tamanho igual, mas com os elementos possivelmente reordenados.
Por exemplo, usando a estratégia null
getter, que é o padrão, classificaremos usando os valores dos elementos em ordem crescente:
use function Zicht itertools iterable ;
$ ordered = iterable ( $ numbers )-> sorted ();
var_dump ( $ ordered );
// {0: 1, 2: 2, 1: 3, 4: 4, 3: 5}
Ou em Twig:
{{ dump ( numbers |it. sorted }}
O algoritmo de classificação preservará as chaves e terá estabilidade garantida. Ou seja, quando os elementos são classificados usando o mesmo valor, é garantido que a ordem de classificação seja igual à ordem dos elementos de entrada. Isso é contrário às funções de classificação padrão do PHP.
Usando a estratégia de fechamento getter, o valor retornado é usado para determinar a ordem. O fechamento é chamado exatamente uma vez por elemento e os valores resultantes devem ser comparáveis. Por exemplo:
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'};
O mapeamentos.php fornece um fechamento de mapeamento que retorna um número aleatório. Isso pode ser usado para classificar uma coleção em ordem aleatória. Por exemplo:
use Zicht itertools util Mappings ;
use function Zicht itertools iterable ;
$ randomized = iterable ( $ words )-> sorted (Mappings:: random ());
var_dump ( $ randomized );
// {... randomly ordere words ...}
Ou em Twig:
{{ dump ( words |it. sorted ( it . mappings . random )) }}
groupBy
converte uma coleção em uma ou mais coleções que agrupam os elementos de acordo com um critério específico.
Por exemplo, usando a estratégia string getter podemos agrupar todos os $vehicles
do mesmo tipo:
use function Zicht itertools iterable ;
$ vehiclesByType = iterable ( $ vehicles )-> groupBy ( ' type ' );
var_dump ( $ vehiclesByType );
// {'bike': {1: [...]}, 'car': {0: [...], 3: [...]} 'unicicle': {2: [...]}}
Ou em Twig:
{{ dump ( vehicles |it. groupBy ( ' type ' )) }}
Não que as chaves originais dos veículos ainda façam parte dos grupos resultantes, e os elementos dentro de cada grupo mantêm a ordem que tinham na entrada, ou seja, utiliza a ordenação estável fornecida pelo sorted
.
reduce
converte uma coleção em um único valor chamando um fechamento de dois argumentos cumulativamente para os elementos da coleção, da esquerda para a direita.
Por exemplo, sem nenhum argumento, reduce
irá somar todos os elementos da coleção:
use function Zicht itertools iterable ;
$ sum = iterable ( $ numbers )-> reduce ();
var_dump ( $ sum );
// 15
Ou em Twig:
{{ dump ( numbers |it. reduce ) }}
No exemplo acima, o fechamento padrão usado é semelhante a este:
public static function add ( $ a , $ b ): Closure
{
return $ a + $ b ;
}
Dado que $numbers
consiste nos elementos {1, 3, 2, 5, 4}, o fechamento add
é chamado quatro vezes:
$ sum = Reductions:: add (Reductions:: add (Reductions:: add (Reductions:: add (( 1 , 3 ), 2 ), 5 ), 4 ));
var_dump ( $ sum );
// 15
Existem vários fechamentos de redução comuns disponíveis em reduções.php. Chamar essas funções retorna um encerramento que pode ser passado para reduction
. Por exemplo:
use Zicht itertools util Reductions ;
use function Zicht itertools iterable ;
$ scentence = iterable ( $ words )-> reduce (Reductions:: join ( ' - ' ));
var_dump ( $ scentence );
// 'Useful - Goonies - oven - Bland - notorious'
Ou em Twig:
{{ dump ( words |it. reduce ( it . reductions . join ( ' - ' )) }}
Outra redução comum é encadear várias listas em uma única lista. Chamamos esse processo de colapso. Este processo também pode ser alcançado usando reduce
e chain
juntos, porém, por ser usado com frequência, o auxiliar collapse
facilita seu uso, por exemplo:
use function Zicht itertools iterable ;
$ flat = iterable ([[ ' one ' , ' two ' ], [ ' three ' ]])-> collapse ();
var_dump ( $ flat );
// {0: 'one', 1: 'two', 0: 'three'}
Ou em Twig:
{% set data = [[ ' one ' , ' two ' ], [ ' three ' ]] %}
{{ dump ( data |it. collapse ) }}