เมธอด filter, map, reduce ของอาเรย์

เมธอด filter map และ reduce นั้นเป็นเมธอดของอาเรย์ คุณสามารถเขียนมันด้วยตัวเองด้วยคำสั่ง for loop แต่การรู้จักกับเมธอดเหล่านี้จะทำให้การทำงานกับอาเรย์ง่ายขึ้นและรวดเร็วขึ้น เนื่องจากมันถูกออกแบบมาเพื่อแก้ปัญหาพื้นฐานที่เรามักต้องการทำกับอาเรย์ นี่เป็นเนื้อหาในบทนี้

  • เมธอด filter
  • เมธอด map
  • เมธอด reduce

เมธอด filter

เมธอด filter ใช้สำหรับเลือกสมาชิกในอาเรย์จากเงื่อนไขที่กำหนด เมธอดรับพารามิเตอร์เป็นฟังก์ชัน Callback วนรอบสมาชิกแต่ละตัวในอาเรย์ และส่งแต่ละค่าดังในอาเรย์เข้ามายังฟังก์ชัน เราต้องสร้างเงื่อนไขโดยส่งค่ากลับเป็น true เพื่อเลือกเอาค่าในอาเรย์ และ false ในกรณีที่ไม่ต้องการ เมธอด filter ส่งค่ากลับเป็นอาเรย์ใหม่ของสมาชิกที่ทำให้เงื่อนไขเป็นจริง

สำหรับตัวอย่างแรกในการใช้งานเมธอด filter มาเขียนโปรแกรมเพื่อเลือกเอาเฉพาะตัวเลขจำนวนคู่ในอาเรย์ นี่เป็นตัวอย่าง

array_filter.js
let numbers = [3, 4, 7, 5, 12, 6, 10, 8, 15];

let evenNumbers = numbers.filter(function (value) {
    return value % 2 == 0;
});

console.log("Filtered:", evenNumbers);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

Filtered: [ 4, 12, 6, 10, 8 ]

ในตัวอย่าง เรามีอาเรย์ของตัวเลข numbers จากนั้นเราต้องการเลือกเอาเพียงตัวเลขจำนวนคู่ในอาเรย์โดยการใช้เมธอด filter เมธอดจะวนแต่ละค่าในอาเรย์และส่งค่าเข้ามายังฟังก์ชัน Callback ผ่านพารามิเตอร์ value เราได้กำหนดเงื่อนไขเพื่อเลือกเอาตัวเลขโดยการส่งค่ากลับด้วยคำสั่ง return

return value % 2 == 0;

นั่นหมายความว่าทุกค่าที่ทำให้เงื่อนไขเป็นจริง จะได้รับการเลือกจากเมธอด filter และเมธอดส่งค่ากลับเป็นอาเรย์ใหม่ของค่าที่ทำให้เงื่อนไขเป็นจริงหรือผ่านการคัดเลือก

ต่อมาเป็นการเลือกเอาออบเจ็คของพนักงานในอาเรย์ โดยเลือกเอาเฉพาะพนักงานที่มีเงินเดือนมากกว่า 50000 บาทขึ้นไปจาก Property salary โดยการใช้เมธอด filter นี่เป็นตัวอย่าง

array_filter2.js
let employees = [
    { name: "Andrew", salary: 62000 },
    { name: "Chris", salary: 53400 },
    { name: "Metin", salary: 32000 },
    { name: "John", salary: 58000 },
    { name: "Julia", salary: 46000 }
];

let hightSalary = employees.filter(function (value) {
    return value.salary >= 50000;
});

console.log("Employees with salary greater than 50000:");
hightSalary.forEach(function (value) {
    console.log(value.name);
});

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

Employees with salary greater than 50000:
Andrew
Chris
John

ในตัวอย่างนี้ เรามีอาเรย์ employees ที่เก็บออบเจ็คของพนักงานที่ประกอบไปด้วยชื่อ name และเงินเดือน salary และเช่นเดิม เพื่อเลือกเอาพนักงานที่มีเงินเดือนมากกว่า 50000 เราต้องสร้างเงื่อนไขที่ส่งค่ากลับเป็นจริงในกรณีที่เงินเดืิอนมากกว่า 50000

hightSalary.forEach(function (value) {
    console.log(value.name);
});

เราจะได้ออบเจ็คที่ตรงตามเงื่อนไขที่ต้องการในอาเรย์ hightSalary จากนั้นใช้เมธอด forEach ในการวนรอบอาเรย์เพื่อแสดงชื่อของพนักงานเหล่านั้นออกมาทางหน้าจอ

นอกจากนี้เมธอด filter ยังส่ง Index ของอาเรย์ผ่านพารามิเตอร์ที่สองเข้าไปยังฟังก์ชัน Callback อีกด้วย ในตัวอย่างนี้เป็นการเลือกเอาตัวเลขในอาเรย์เฉพาะสมาชิกที่มี Index น้อยกว่า 5

array_filter3.js
let numbers = [10, 20, 30, 40, 50, 60, 70, 80];

let minorIndexed = numbers.filter(function (value, index) {
    return index < 5;
});

console.log(minorIndexed);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

[ 10, 20, 30, 40, 50 ]

นอกจากจะใช้ค่าของอาเรย์เป็นเงื่อนไขแล้ว เราสามารถใช้ Index เป็นเงื่อนไขได้ โดยรับจากพารามิเตอร์ที่สองของฟังก์ชัน Callback ในกรณีนี้ ตัวเลขที่มี Index น้อยกว่า 5 เท่านั้นที่จะถูกเลือกจากเมธอด filter

เมธอด map

เมธอด map ใช้สำหรับแปลงค่าในอาเรย์ให้เป็นค่าใหม่ที่เกิดจากการส่งค่ากลับของฟังก์ชัน Callback ที่ส่งเข้าไปยังเมธอด โดยการวนแต่ละค่าในอาเรย์เหมือนกับเมธอด filter และค่าที่ส่งกลับจากฟังก์ชัน Callback จะกลายมาเป็นค่าใหม่ของอาเรย์แทน

นี่เป็นตัวอย่างของการแปลงตัวเลขในอาเรย์ให้เพิ่มขึ้นเป็นสองเท่าโดยการใช้เมธอด map

array_map.js
let numbers = [1, 2, 3, 4, 5, 6, 7, 8];

let doubledNumbers = numbers.map(function (value, index) {
    return value * 2;
});

console.log("Doubled:", doubledNumbers);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

Doubled: [
   2,  4,  6,  8,
  10, 12, 14, 16
]

ในตัวอย่าง เราได้ส่งค่ากลับจากฟังก์ชัน Callback โดยการคูณค่าในอาเรย์ด้วย 2 จากคำสั่ง value * 2 เพื่อทำให้มันเพิ่มขึ้นเป็นสองเท่า และตอนนี้เราได้อาเรย์ใหม่ doubledNumbers ที่มีตัวเลขเพิ่มขึ้นเป็นสองเท่าจากอาเรย์เดิมแล้ว

เมธอด map นั้นส่ง Index ของอาเรย์เป็นพารามิเตอร์ที่สองของฟังก์ชันเช่นเดียวกันกับเมธอด filter และในกรณีที่เราไม่ต้องการใช้งานมันสามารถละเว้นออกไปได้

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

array_map2.js
let names = ["Andrew", "Chris", "Metin", "John", "Brendan"];

let objects = names.map(function (value, index) {
    return {
        id: index + 1,
        name: value
    }
});

console.log(objects);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

[
  { id: 1, name: 'Andrew' },
  { id: 2, name: 'Chris' },
  { id: 3, name: 'Metin' },
  { id: 4, name: 'John' },
  { id: 5, name: 'Brendan' }
]

เราสามารถใช้เมธอด map เพื่อแปลงค่าในอาเรย์เป็นค่าใดๆ ได้ ในตัวอย่างนี้เราได้แปลงอาเรย์เป็นออบเจ็ค โดยใช้ Index เป็นรหัส และชื่อในอาเรย์ จะเห็นว่าเราสามารถแปลงค่าเป็นแบบไหนก็ได้ เพียงส่งกลับเป็นค่าใหม่ที่ต้องการจากฟังก์ชัน Callback

เมธอด reduce

เมธอด reduce เป็นเมธอดที่เรียกใช้งานฟังก์ชัน Reducer ที่ส่งเป็นฟังก์ชัน Callback เข้าไปยังเมธอด และส่งค่ากลับเป็นผลจากการทำงานของฟังก์ชัน Reducer กับค่าทั้งหมดในอาเรย์แบบต่อเนื่องกัน และได้ผลลัพธ์เป็นค่าสุดท้ายเพียงค่าเดียว

สำหรับตัวอย่างพื้นฐานที่จะช่วยให้เข้าใจการทำงานของเมธอด reduce ได้ดีที่สุดคือใช้มันสำหรับหาผลรวมของตัวเลขในอาเรย์ นี่เป็นตัวอย่าง

array_sum.js
let numbers = [0, 1, 2, 3, 4];
let sum = numbers.reduce(function (accumulator, currentValue) {
    return accumulator + currentValue;
}, 0);

console.log("Sum:", sum);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

Sum: 10

ในตัวอย่าง เป็นการใช้งานเมธอด reduce เพื่อหาผลรวมของตัวเลขในอาเรย์ เมธอดรับฟังก์ชัน Callback เป็นพารามิเตอร์แรก และพารามิเตอร์ที่สองเป็นค่าเริ่มต้นสำหรับเมธอดเพื่อทำงาน ในตัวอย่างเราได้กำหนดเป็น 0 เพื่อเป็นค่าเริ่มต้นสำหรับหาผลรวมของตัวเลขในอาเรย์

ในการทำงานเมธอดจะวนทุกค่าในอาเรย์และส่งค่าเข้าไปยังฟังก์ชัน Callback ผ่านพารามิเตอร์ currentValue

function (accumulator, currentValue) {
    return accumulator + currentValue;
}

ในรอบแรกของการทำงาน accumulator จะมีค่าเป็น 0 ซึ่งเป็นค่าเริ่มที่กำหนดให้กับเมธอด และค่าที่ส่งกลับในฟังก์ชันจะกลายมาเป็น accumulator ในรอบถัดไป และโปรแกรมวนทำจนถึงสมาชิกตัวสุดท้ายในอาเรย์ และค่าส่งกลับในรอบสุดท้ายจะเป็นผลลัพธ์ของเมธอด

สำหรับการทำงานของเมธอด reduce เพื่อหาผลรวมของตัวเลขในอาเรย์จากตัวอย่างด้านบน สามารถแสดงให้เห็นในแต่ละขึ้นตอนได้ดังตารางต่อไปนี้

รอบที่ accumulator currentValue ค่าส่งกลับ
1 0 0 0 + 0
2 0 1 0 + 1
3 1 2 1 + 2
4 3 3 3 + 3
5 6 4 6 + 4 => 10

จากในตารางนั้นจะเห็นว่าเมธอด reduce ทำงานทั้งหมด 5 ในรอบแรก accumulator มีค่าเริ่มต้นเท่ากับ 0 และนำไปบวกกับค่าในรอบปัจจุบัน ค่าที่ถูกส่งกลับจะกลายเป็น accumulator ในรอบถัดไปเรื่อยๆ จนถึงการส่งกลับในรอบสุดท้ายซึ่งก็คือผลลัพธ์การทำงานของเมธอด

ในตัวอย่างถัดมาลองมาเปลี่ยนค่าเริ่มต้นในอาร์กิวเมนต์ที่สองของเมธอดเป็น 10 และนั่นจะทำให้มันถูกใช้เป็น accumulator ในรอบแรก นี่เป็นตัวอย่าง

array_sum2.js
let numbers = [0, 1, 2, 3, 4];
let sum = numbers.reduce(function (accumulator, currentValue) {
    return accumulator + currentValue;
}, 10);

console.log("Sum:", sum);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

Sum: 20

ในตัวอย่างนั้นคุณคงจะสามารถเดาได้ว่าทำไม เนื่องจากว่าเริ่มต้นเรากำหนดค่าเริ่มให้กับฟังก์ชัน Reducer เป็น 10 นั่นทำให้ค่า accumulator ในรอบแรกเริ่มจาก 10 นั้นเอง ซึ่งสามารถแสดงการทำงานได้ดังตารางต่อไปนี้

รอบที่ accumulator currentValue ค่าส่งกลับ
1 10 0 10 + 0
2 10 1 10 + 1
3 11 2 11 + 2
4 13 3 13 + 3
5 16 4 16 + 4 => 20

นอกจากนี้ ในการใช้งานเมธอด reduce นั้นยังสามารถละเว้นค่าเริ่มต้นในพารามิเตอร์ที่สองได้ ถ้าหากเราทำ ค่าแรกในอาเรย์จะถูกนำมาใช้เป็นค่าเริ่มต้นแทน และอาเรย์จะเริ่มทำงานตั้งแต่สมาชิกตัวที่สองเป็นต้นไป นี่เป็นตัวอย่าง

array_sum3.js
let numbers = [0, 1, 2, 3, 4];
let sum = numbers.reduce(function (accumulator, currentValue) {
    return accumulator + currentValue;
});

console.log("Sum:", sum);   // Sum: 10

ในตัวอย่างนี้ เป็นโปรแกรมสำหรับหาผลรวมของตัวเลขในอาเรย์เช่นเดิม จะเห็นว่าผลลัพธ์การทำงานยังคงเป็นเท่าเดิม โปรแกรมเริ่มวนจากสมาชิกตัวที่สอง (1) ในอาเรย์ และใช้สมาชิก (0) เป็นค่าเริ่มต้นสำหรับ accumulator ในรอบแรกแทน

เมธอด reduce นั้นสามารถนำมาประยุกต์ใช้เพื่อแก้ปัญหาต่างๆ ได้หลายอย่าง ข้อดีของมันคือเราสามารถกำหนดฟังก์ชัน Reducer ซึ่งเป็นฟังก์ชัน Callback ที่สามารถทำงานเสร็จได้ในตัวของมันเอง และยังกระทัดรัดและสั้นในการเขียน ในตัวอย่างนี้เป็นการใช้เมธอด reduce เพื่อหาค่ามากสุดและน้อยสุดในอาเรย์ของตัวเลข

reduce_max_min.js
let numbers = [10, 5, 2, 17, 16, 6, 18, 3];

let max = numbers.reduce(function (accumulator, currentValue) {
    return accumulator > currentValue ? accumulator : currentValue;
});

let min = numbers.reduce(function (accumulator, currentValue) {
    return accumulator < currentValue ? accumulator : currentValue;
});

console.log("Max:", max);
console.log("Min:", min);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

Max: 18
Min: 2

ในกรณีนี้ไม่จำเป็นต้องกำหนดค่าเริ่มต้นให้กับเมธอด reduce เนื่องจากว่าเราต้องการนำแต่ละค่าในอาเรย์มาเปรียบเทียบกันเอง และส่งค่ากลับเป็นค่าที่มากกว่าหรือน้อยกว่าเสมอ ดังนั้นโปรแกรมเริ่มทำงานจากสมาชิกตัวที่สองของอาเรย์ซึ่งคือ 5 และใช้สมาชิกตัวแรก 10 เป็นค่าเริ่มต้นของ accumulator

return accumulator > currentValue ? accumulator : currentValue;
...
return accumulator < currentValue ? accumulator : currentValue;

ในแต่ละรอบของการทำงานเมธอดจะส่งกลับเป็นค่าที่น้อยกว่าหรือมากกว่าเสมอ นั่นทำให้ในตอนสุดท้ายผลลัพธ์ของโปรแกรมจะได้ค่าที่น้อยกว่าและมากกว่าที่เราต้องการหาจากอาเรย์ด้วยเมธอด reduce

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

counting_elements.js
let colors = [
    "red", "green", "yellow", "green", "blue", "red", "green"
];

let count = colors.reduce(function(object, currentValue, index) {
    if (typeof object[currentValue] === 'undefined') {
        object[currentValue] = 1;
    } else {
        object[currentValue]++;
    }
    return object;
}, {});

console.log('counted:', count);

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

counted: { red: 2, green: 3, yellow: 1, blue: 1 }

ในตัวอย่างนี้ เป็นโปรแกรมสำหรับนับสีในอาเรย์ว่าในแต่ละสีนั้นมีจำนวนเท่าไร และเนื่องจากเราใช้ออบเจ็คสำหรับเก็บการนับ ดังนั้นค่าเริ่มของเมธอดในอาร์กิวเมนต์ที่สองจึงเป็นออบเจ็คที่ว่างเปล่า {} จากนั้น Property ของออบเจ็คจะถูกสร้างขึ้นมาแบบไดนามิกส์ตามค่าที่มีอยู่ในอาเรย์

if (typeof object[currentValue] === 'undefined') {
    object[currentValue] = 1;
} else {
    object[currentValue]++;
}

ในฟังก์ชัน Reducer เราได้ทำการตรวจสอบโดยการใช้ค่าของอาเรย์เป็น Key ว่ามันเคยถูกนับแล้วหรือไม่ โดยตรวจสอบว่ามี Property นี้อยู่แล้วหรือยัง ถ้าหากไม่เริ่มนับมันจาก 1 หรือในกรณีทีมีแล้วเพิ่มค่าขึ้นไปอีก 1

return object;

เนื่องจากออบเจ็คนั้นเก็บค่าในรูปแบบ Reference ดังนั้นค่าที่ส่งกลับจะเป็นออบเจ็คเดิมเสมอ และในตอนท้ายเราจะได้ค่าที่นับได้ทั้งหมดเป็นออบเจ็คที่มีชื่อของสีเป็น Key ในตัวแปร count

การกำหนดค่าเริ่มต้นหรือไม่นั้นอาจให้ผลลัพธ์ที่แตกต่างกันขึ้นอยู่กับว่าฟังก์ชัน Reducer ของคุณทำอะไร เช่น ในตัวอย่างการหาผลรวมเนื่องจากทั้งสองวิธี (กำหนดค่าเริ่มต้นเป็น 0 หรือไม่กำหนด) นั้นให้ผลลัพธ์เหมือนกัน แต่ในบางกรณีเช่นการหาค่ามากกว่าหรือน้อยกว่าในอาเรย์ การกำหนดค่าเริ่มต้นอาจทำให้ผลลัพธ์การทำงานไม่ถูกต้องได้

ในตอนนี้คุณคงจะเข้าใจแล้วว่าจะนำเมธอดเหล่านี้มาช่วยอำนวยความสะดวกในการเขียนโปรแกรมอย่างไร มาสรุปกันอีกครั้งว่าแต่ละเมธอดนั้นใช้ทำอะไร

  • เมธอด filter ใช้สำหรับเลือกค่าในอาเรย์จากเงื่อนไขที่กำหนด
  • เมธอด map ใช้สำหรับแปลงค่าในอาเรย์เดิมเป็นค่าใหม่
  • เมธอด reduce ใช้เพื่อวนรอบอาเรย์เพื่อคำนวณค่าแบบต่อเนื่องและส่งค่ากลับเป็นค่าสุดท้าย

ในบทนี้ คุณได้เรียนรู้เกี่ยวกับการใช้งานเมธอด filter map และ reduce ของอาเรย์ในภาษา JavaScript ที่สามารถอำนวยความสะดวกเมื่อต้องทำงานกับอาเรย์