Map Filter

โดยทั่วไปแล้ว List ตั้งต้นมักไม่ค่อยมีประโยชน์ที่จะเอาไปใช้ต่อเท่าไหร่ จนกว่าเราจะเปลี่ยนค่าของสมาชิกบางตัวไปตามเราที่ต้องการ

เราสามารถสร้าง List ใหม่จากของเดิมได้ โดยคำนวณค่าสมาชิกเก่าทุกตัวภายใต้ฟังก์ชันเดียวกัน วิธีการนี้เรียกว่า list comprehension และสามารถทำได้ดังนี้

    ghci> [2 * x^2 | x <- [1..10]]
    [2,8,18,32,50,72,98,128,162,200]
    ghci> [[a] ++ [v] | a <- "kg", v <- "aiueo"]
    ["ka","ki","ku","ke","ko","ga","gi","gu","ge","go"]

นอกจากนี้ เรายังสามารถกรองสมาชิกตัวที่ไม่ต้องการทิ้งก่อนเอาไปคำนวณไปได้ เช่น

    ghci> [2 * x^2 | x <- [1..10], odd x]
    [2,18,50,98,162]
    ghci> [2 * x^2 | x <- [1..10], x < 5]
    [2,8,18,32]

อย่างไรก็ตาม ถ้าต้องทำงานกับ List อนันต์ (อย่าง [1..]) การกรองสมาชิกด้วยวิธีการข้างต้นนี้ไม่พอ ต้องใช้งานร่วมกับ take, takeWhile เช่นเดิมครับ


นอกจาก list comprehension ยังมีทางเลือกที่ช่วยให้ทำงานได้เช่นเดียวกันคือ map กับ filter ครับ

    ghci> map (^2) [1..10]
    [1,4,9,16,25,36,49,64,81,100]
    ghci> map (*2) (map (^2) [1..10])
    [2,8,18,32,50,72,98,128,162,200]
    ghci> map (*2) (map (^2) (filter odd [1..10]))
    [2,18,50,98,162]

ข้อแตกต่างหลักๆ คือ list comprehension จะทำงานกับ List หลายๆ อัน (มองในรูป Cartesian product) ได้ง่ายกว่า แต่การใช้ฟังก์ชัน map, filter แยกกัน จะเป็นธรรมชาติกว่าเมื่อทำ filter หลังจาก map เช่น

    ghci> filter (/="wu") [[a] ++ [v] | a <- "w", v <- "aeiou"]
    ["wa","we","wi","wo"]

ตัวอย่างเลื่องชื่อของ Haskell อย่าง quicksort ก็สามารถทำโดยใช้เทคนิค filter ร่วมกับการทำ pattern matching บน List ดังนี้ครับ

    quicksort []     = []
    quicksort (x:xs) = quicksort lesser ++ [x] ++ quicksort greater
        where lesser  = filter (<x)  xs
              greater = filter (>=x) xs

Nattawut Phetmak

Jack of all Trades

blog comments powered by Disqus