จัดการข้อมูลด้วย Sequence

Christopher Hay-Yin Ng
Black Lens
Published in
2 min readMar 26, 2018

--

ทุกท่านคงจะคุ้นเคยกันดีกับ data type ประเภท Collection ที่ใช้ในการเก็บชุดข้อมูลประเภท type เดียวกัน ซึ่งก็มี implementation มากมาย เช่น ArrayList, HashMap

วันนี้ผมจะมานำเสนอ Sequence อีกหนึ่ง type ทางเลือกในการจัดการข้อมูล

Sequence คืออะไร

Kotlin doc ได้ให้คำอธิบายสั้นๆประมาณนี้

A sequence that returns values through its iterator. The values are evaluated lazily, and the sequence is potentially infinite.

Sequence คือ type ที่สามารถเข้าถึงข้อมูลแบบ lazily ตามปกติแล้วถ้าใช้ type ประเภท Iterable อื่นๆ เมื่อมีการกระทำบางอย่าง ตัว Iterator จะเรียกข้อมูลมาใช้งานทันที แต่ใน Sequnce นั้นจะเรียกข้อมูลเมื่อถึงเวลาจำเป็นเท่านั้น หรือก็คือเมื่อถึง terminal operation นั้นเอง ว่าไปก็คล้ายกับ Stream ของ Java 8

ผลที่ได้จากการรัน code ชุดนี้

สังเกตุว่า List นั้นจะมีการเรียก Filter และ Map เรียบร้อยแล้ว แต่ Sequence และ Stream นั้นยังไม่มีการกระทำอะไร เนื่องจากยังไม่มี terminal operation

Terminal operation มีอะไรบ้าง

Operation ประเภทนี้ก็คือ operation ที่ Sequence ไม่ได้ return Sequence ออกมา หรือก็คือ operation สุดท้ายที่มันจะทำงาน เช่น sum(), first(), forEach() เมื่อเจอ operation เหล่านี้ ถึงจะเริ่มการเรียก operation ต่างๆที่เตรียมไว้

ทำงานแบบเรียงข้อมูล

อีกจุดที่ Sequence ทำงานต่างกับ Collection ปกติ นั้นคือการเรียกใช้งานข้อมูลแบบ 1 อันต่อครั้ง แล้วนำข้อมูลนั้นเรียก operation ต่างๆจนเสร็จ ถึงจะไปข้อมูลต่อไป

ถ้าเป็น List หรือ Map เมื่อเกิด operation จะรอทำจนครบทั้งชุดข้อมูลก่อนที่จะไป operation ต่อไป จากข้างต้นคือรอ filter() จนเสร็จแล้วค่อยไป map()

การทำงานของ Sequence จะเป็นแนวตั้ง เรียง operation ให้ครบถึงจะไปข้อมูลต่อไป

เมื่อลองรัน code ชุดนี้ผลที่ได้จากเป็นดังนี้

ต่างกับ Stream ยังไง

พอมาถึงตรงนี้ หลายท่านคงสงสัยว่า แล้วมันต่างจาก Stream ใน Java 8 ยังไง จุดที่ต่างกันหลักๆเลยคือ Stream ไม่สามารถนำมาใช้ซ้ำได้ ถ้าเอามาใช้อีกรอบจะเกิด

java.lang.IllegalStateException: stream has already been operated upon or closed

แต่ Sequence สามารถใช้ซ้ำได้เรื่อยๆ อีกจุดที่ต่างกันคือ Stream รองรับ Parallel ด้วย parallelStream() แต่ Sequence ไม่มี

ควรใช้ Sequence เมื่อไหร่

  1. เมื่อมีการเรียก chaining operations เยอะๆ เพราะการเรียก map(), filter() สิ่งที่เกิดขึ้นคือ Kotlin จะสร้าง loop ขึ้นมา จาก code ข้างต้น มี 1 map() และ 1 filter() จะเกิดทั้งหมด 2 loop ซึ่งจะดูสูญเปล่ามาก เพราะถ้าเขียนด้วย imparative style เราสามารถจบได้ใน loop เดียว แต่ตัว Sequence นั้นจะมี Iterator ตัวเดียว ในการรันจนจบ
  2. ใช้ first(), หรือ last() operation สองตัวนี้มีความเหมือนกันคือต้องการหาตัวแรกหรือตัวสุดท้ายที่ผ่านเงื่อนไขต่างๆ เพราะฉะนั้นแทนที่จะไล่ทำงานครบทั้งชุดข้อมูล ก็เปลี่ยนเป็นทำทีละตัวจนเจอตัวที่ผ่านเงื่อนไขก็พอ
  3. ในแง่ของการ debug จะช่วยได้มากในการที่เราต้องการเช็คการทำงาน ในกรณีที่มี operation ซ้อนมากๆ จะทำให้เห็น flow การทำงานที่ชัดเจนขึ้น

ถ้ามี List หรือ Map อยู่ จะทำยังไง

Sequence เป็น type ที่รองรับในกลุ่ม Collection ต่างๆใน Kotlin ทำให้สามารถแปลง type เช่น List, Map เป็น Sequence ได้ทันที

listOf(1, 2, 3).asSequence()
mapOf("foo" to "bar").asSequence()

หรือจะแปลงกลับเป็น MutableList ก็ได้

sequenceOf(1, 2, 3).toMutableList()

จบโฆษณา Sequence เพียงเท่านี้ Happy Kotlin ครับ

--

--