Reduce - האולר השווייצרי של טיפול במערכים של JavaScript

מחבר:
בתאריך:

הפונקציה reduce של JavaScript

זה המדריך החמישי בסדרה שמוקדשת ללימוד פונקציות של JavaScript שפועלות על מערכים. המדריכים הקודמים הניחו את היסודות למדריך זה, ולכן מומלץ לקרוא אותם:

  • foreach שהיא דרך אלגנטית לכתוב לולאה של JavaScript.
  • סינון מערכים ב JavaScript-באמצעות הפונקציה filter
  • טרנספורמציה של מערכים ב-JavaScript באמצעות הפונקציה map
  • sort מאפשר לנו לסדר מערך לפי סדר. לדוגמה, לסדר פריטים של מערך מספרים מערך גבוה לנמוך. או הפוך.

 

הפונקציה reduce של JavaScript

הפונקציה reduce היא החזקה והמגוונת ביותר מבין הפונקציות שמטפלות במערכים. היא מאפשרת לנו להפוך מערך של ערכים לערך אחד. reduce עוברת בלולאה על כל אחד מהפריטים, ומפעילה פונקציה במטרה לצבור את הערכים לתוך ערך יחיד, total, שיכול להיות מספר, מחרוזת, מערך או אובייקט.

יהיה יותר פשוט אם נלמד באמצעות דוגמאות מועילות:

 

סכום של מערך מספרים באמצעות reduce

בדוגמה הבאה אנחנו רוצים לקבל את סכום המספרים שמסודרים במערך של מספרים.

הפונקציה reduce מקבלת שני פרמטרים:

  • פונקציה שמבצעת פעולה על כל פריט של המערך.
    פונקציה זו מקבלת 2 ערכים:
    1. צובר (total) שבו מצטברים הערכים שמתווספים בכל פעם שהלולאה רצה
    2. הפריט הנוכחי (item)
  • ערך התחלתי - הפונקציה מתחילה לצבור מערך שאותו אנחנו צריכים להגדיר מראש.
let numbers = [9, 41, 6, 78];
let res = numbers.reduce(function(total, item) {
    return total + item
}, 0);
console.log(res); // 134

בדוגמה שלנו, אנחנו רוצים לסכום את המספרים שנמצאים במערך המספרים numbers כדי לקבל את הסה"כ. לשם כך, reduce עוברת על כל אחד מפריטי המערך בלולאה, ועבור כל פריט קוראת לפונקציה אנונימית שמחזירה את הערך הצבור (total) בתוספת הפריט הנוכחי. ה-total מתחיל מ-0, ובכל פעם שהלולאה רצה מתווסף הערך התורן עד שמצטבר הסה"כ.

ואפשר לכתוב את אותה הפונקציה באופן אלגנטי יותר באמצעות תחביר fat arrow של ES6:

let res   = numbers.reduce((total, item) => {return total + item}, 0);

שני דברים שכדאי לשים אליהם לב:

  1. הפונקציה האנונימית צריכה להחזיר ערך אז תמיד להקפיד שיהיה return.
  2. להוסיף את הערך ההתחלתי שממנו מתחילה הפונקציה לצבור את הסה"כ. במקרה זה השתמשנו ב-0. אם לא נקפיד על על שימוש בערך התחלתי, הפונקציה תנסה למצוא ערך כזה, ואז לא בטוח שנקבל את התוצאה הרצויה.

כפי שניתן לסכום מערך של מספרים, ניתן למצות סכום של מספרים מתוך מערך שבו כל פריט מכיל מספר שדות.

בדוגמה הבאה, אנחנו מעוניינים למצוא את השווי של צי מכוניות.

let cars = [
  {
    name  : 'Toyota',
    price : 140000,
    number: 3
  },
  {
    name  : 'BMW',
    price : 190000,
    number: 6
  },
  {
    name  : 'Sussita',
    price : 4000,
    number: 1
  }
];

let res = cars.reduce( (total, item) => {
  return total + item.price * item.number;
}, 0);

console.log(res); // 1564000

בכל פעם שהלולאה רצה, מוכפל מספר המכוניות מכל סוג במחיר, ואז מתווסף ל-total, שמתחיל מ-0.

ואפשר להיות קצת יותר מתוחכמים ולסכום את הפריטים שאינם סוסיתא.

let res = cars.reduce( (total, item) => {
  return item.name !== 'Sussita'? total + item.price * item.number : total;
}, 0);

עד כה ראינו דוגמאות שבהם הסה"כ הוא מספר. אבל קיימות אפשרויות נוספות. אנחנו יכולים להשתמש במחרוזת, במערך או באובייקט.

 

מציאת מספר הפריטים מכל סוג באמצעות reduce

בדוגמה הבאה, אנחנו מעוניינים לסכום את מספר הפריטים מכל סוג. לשם כך, נסדר את הערכים בתוך אובייקט שבו כל פריט מורכב מ-key שהוא שם, ו-value שהוא מספר הפריטים בעלי אותו שם.

// Creating a tally with reduce
let cars = ['Honda', 'Toyota', 'Sussita', 'Tesla', 'BMW', 'Toyota', 'Honda', 'Mitsubishi'];
let res = cars.reduce( (total, item) => {
  total[item] = (total[item] || 0) + 1 ;
  return total;
} , {});
console.log(res); // {BMW:1, Honda:2, Mitsubishi:1, Sussita:1, Tesla:1, Toyota:2}

במידה והפריט אינו קיים הוא יקבל את הערך 0, ואם הפריט כבר קיים יתווסף לערך 1.

 

שיטוח מערך רב ממדי באמצעות reduce

בדוגמה הבאה, נשתמש ב-reduce כדי לשטח מערך רב-ממדי, ולהפוך אותו למערך בממד אחד.

// Flattening an array of arrays with reduce
let letters = [['a', 'b', 'c'], ['o','e','i']];
let res = letters.reduce((total, item) => {
  return total.concat(item);
}, []); // ["a", "b", "c", "o", "e", "i"]
console.log(res);

בכל פעם שהלולאה רצה, מתווסף הפריט התורן למערך res.

 

הרצת מספר פונקציות שמכונסות ביחד במערך כדי לקבל את התוצאה הרצויה

ב-JavaScript פונקציות הם ערכים, ולכן אפשר לכנס פונקציות לתוך מערך.

פונקציות הם ערכים בגלל שאפשר לכתוב כך:

let split = (input) => input.split("");

וערכים ניתן לשלב לתוך מערך.

נשתמש בתכונה זו כדי להפוך את כיוונה של מחרוזת. מסוג הדברים שיכולים להועיל כשעובדים עם עברית.

let split       = (input) => input.split("");
let reverse = (input) => input.reverse();
let join       = (input) => input.join("");

let pipeline = [split, reverse, join];
let result   = pipeline.reduce((total, item) => {return item(total)}, "000,1");
console.log(result); // 1,000

3 הפונקציות שישמשו אותנו לביצוע המשימה הם:

  • split שעם הפרמטר של מחרוזות ריקה מפרק מחרוזת למערך.
  • reverse שהופך את כיוונו של המערך (פריט ראשון הופך לאחרון).
  • הפונקציה join שמצרפת מערך למחרוזת.

את שלושת הפונקציות כינסנו למערך ששמו pipeline

השתמשנו ב-reduce כדי להפעיל את הפונקציות במערך לפי סדר, במטרה להפוך את המחרוזת "000,1" ל-"1,000".

 

צירוף פונקציות

היופי בפונקציות שאנחנו לומדים שניתן לצרף אותם אחת לשנייה, ולהשיג הרבה מאוד בקוד מאוד קצר.

לדוגמה, הקוד הבא שבאמצעותו נחשב את הערך הכולל של המכוניות בש"ח בתנאי שמחיר המכונית גבוה מ-4000.

let sum = cars
  .filter((item) => (item.price > 40000))
  .map((item)    => item.price * 3.5)
  .reduce((total, item) => {return total + item}, 0);

נסביר מה עשינו:

  • קודם כל, סיננו את הפריטים שמחירם גבוה מ-400 באמצעות filter
  • ואח"כ כפלנו ב-3.5, וקיבלנו את המחיר בשקלים באמצעות הפונקציה map
  • ובסוף השתמשנו ב-reduce כדי לקבל את הסה"כ

מדריכי JavaScript למתקדמים

 

אהבתם? לא אהבתם? דרגו!

0 הצבעות, ממוצע 0 מתוך 5 כוכבים

 

הוסף תגובה חדשה

 

= 5 + 4

תמונת המגיב

רוברט בתאריך: 31.03.2018

דוגמה מצוינת. תודה רבה.