迭代器工具(簡稱itertools )是一組方便的工具,用於處理資料序列(例如陣列、迭代器和字串)。一些命名和 API 是基於 Python itertools的。
範例
常見的操作包括:
map
和mapBy
filter
、 difference
sorted
groupBy
accumulate
、 collapse
和reduce
為了透過 Twig 使用可用的itertools篩選器/函數,只需在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'}
或在樹枝中:
{{ 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}
或在樹枝中:
{{ 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'}
或在樹枝中:
{{ 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}
或在樹枝中:
{{ dump ( vehicles |it. map ( ' colors.2 ' )) }}
使用迭代器工具的一種方法是將陣列、迭代器、字串等轉換為IterableIterator
。此類別為所有常見操作提供了流暢的介面。例如:
use function Zicht itertools iterable ;
$ result = iterable ( $ vehicles )-> filter ( ' is_cool ' )-> mapBy ( ' id ' )-> map ( ' type ' );
var_dump ( $ result );
// {5: 'unicicle', 9: 'car'}
或在樹枝中:
{{ 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'}
使用字串 getter 策略,我們可以輕鬆取得由車輛識別碼映射的$vehicles
中每個元素的類型。例如:
use function Zicht itertools iterable ;
$ types = iterable ( $ vehicles )-> mapBy ( ' id ' )-> map ( ' type ' );
var_dump ( $ types );
// {1: 'car', 2: 'bike', 5: 'unicicle', 9: 'car'}
或在樹枝中:
{{ 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}
或在樹枝中:
{{ 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'}
或在樹枝中:
{{ dump ( vehicles |it. filter ( vehicle => vehicle . price >= 10000 ).map( ' type ' )) }}
使用字串 getter 策略,我們只能取得被認為很酷的$vehicles
。例如:
use function Zicht itertools iterable ;
$ coolVehicleTypes = iterable ( $ vehicles )-> filter ( ' is_cool ' )-> map ( ' type ' );
var_dump ( $ coolVehicleTypes );
// {5: 'unicicle', 9: 'car'}
或在樹枝中:
{{ dump ( vehicles |it. filter ( ' is_cool ' ).map( ' type ' )) }}
filters.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'}
或在樹枝中:
{{ dump ( words |it. filter ( it . filters . in ([ ' Shining ' , " My little pony', 'Goonies'])) }}
sorted
將一個集合轉換為另一個大小相等但元素可能重新排序的集合。
例如,使用預設的null
getter 策略,我們將使用元素值按升序進行排序:
use function Zicht itertools iterable ;
$ ordered = iterable ( $ numbers )-> sorted ();
var_dump ( $ ordered );
// {0: 1, 2: 2, 1: 3, 4: 4, 3: 5}
或在樹枝中:
{{ dump ( numbers |it. sorted }}
排序演算法將保留鍵並保證穩定。即,當使用相同值對元素進行排序時,則保證排序順序與輸入元素的順序相同。這與標準的 PHP 排序函數相反。
使用閉包 getter 策略,傳回值用於確定順序。每個元素只呼叫一次閉包,結果值必須是可比較的。例如:
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 ...}
或在樹枝中:
{{ dump ( words |it. sorted ( it . mappings . random )) }}
groupBy
將一個集合轉換為一個或多個集合,這些集合根據特定條件將元素分組在一起。
例如,使用字串 getter 策略,我們可以將所有相同類型的$vehicles
分組在一起:
use function Zicht itertools iterable ;
$ vehiclesByType = iterable ( $ vehicles )-> groupBy ( ' type ' );
var_dump ( $ vehiclesByType );
// {'bike': {1: [...]}, 'car': {0: [...], 3: [...]} 'unicicle': {2: [...]}}
或在樹枝中:
{{ dump ( vehicles |it. groupBy ( ' type ' )) }}
並不是說車輛的原始鍵仍然是結果組的一部分,並且每個組中的元素保持它們在輸入中的順序,即它使用sorted
提供的穩定排序。
reduce
透過從左到右對集合中的元素累積調用兩個參數的閉包,將集合轉換為單一值。
例如,在沒有任何參數的情況下, reduce
會將集合的所有元素加在一起:
use function Zicht itertools iterable ;
$ sum = iterable ( $ numbers )-> reduce ();
var_dump ( $ sum );
// 15
或在樹枝中:
{{ 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
reductions.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'
或在樹枝中:
{{ 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'}
或在樹枝中:
{% set data = [[ ' one ' , ' two ' ], [ ' three ' ]] %}
{{ dump ( data |it. collapse ) }}