เครื่องมือ Iterator หรือเรียกสั้นๆ ว่า 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'}
หรือในทวิก:
{{ 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 ' )) }}
วิธีหนึ่งในการใช้เครื่องมือ 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'}
หรือในทวิก:
{{ 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'}
การใช้กลยุทธ์ string 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 ' )) }}
การใช้กลยุทธ์ string 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 ' )) }}
มีการปิดตัวกรองทั่วไปหลายอย่างใน 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'}
หรือในทวิก:
{{ dump ( words |it. filter ( it . filters . in ([ ' Shining ' , " My little pony', 'Goonies'])) }}
sorted
แปลงคอลเลกชันหนึ่งเป็นคอลเลกชันอื่นที่มีขนาดเท่ากัน แต่มีองค์ประกอบที่อาจเรียงลำดับใหม่
ตัวอย่างเช่น การใช้กลยุทธ์ getter null
ซึ่งเป็นค่าเริ่มต้น เราจะจัดเรียงโดยใช้ค่าองค์ประกอบตามลำดับจากน้อยไปหามาก:
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 มาตรฐาน
การใช้กลยุทธ์การปิดรับค่าที่ส่งคืนจะถูกใช้เพื่อกำหนดลำดับ การปิดจะถูกเรียกหนึ่งครั้งต่อองค์ประกอบ และค่าผลลัพธ์จะต้องเปรียบเทียบได้ ตัวอย่างเช่น:
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
แปลงหนึ่งคอลเลกชันเป็นหนึ่งคอลเลกชันหรือมากกว่าที่จัดกลุ่มองค์ประกอบเข้าด้วยกันตามเกณฑ์เฉพาะ
ตัวอย่างเช่น การใช้กลยุทธ์ string 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 ) }}