دليل لأسلوب التخفيض في جافا سكريبت

تعد طريقة تقليل JavaScript أحد الركائز الأساسية للبرمجة الوظيفية.دعنا نستكشف كيف يعمل ، ومتى يجب استخدامه ، وبعض الأشياء الرائعة التي يمكنه القيام بها.

تخفيض أساسي

استخدمه عندما : لديك مجموعة من المبالغ وتريد إضافتها جميعًا.

const euros = [29.76, 41.85, 46.5]; const sum = euros.reduce((total, amount) => total + amount); sum // 118.11

كيفية استخدامها:

  • في هذا المثال ، يقبل Reduce معلمتين ، الإجمالي والمبلغ الحالي.
  • يتنقل أسلوب الاختزال عبر كل رقم في المصفوفة كما هو الحال في حلقة for-loop.
  • عندما تبدأ الحلقة تكون القيمة الإجمالية هي الرقم الموجود في أقصى اليسار (29.76) والمبلغ الحالي هو الذي بجانبها (41.85).
  • في هذا المثال بالذات ، نريد إضافة المبلغ الحالي إلى الإجمالي.
  • يتم تكرار الحساب لكل مبلغ في المصفوفة ، ولكن في كل مرة تتغير القيمة الحالية إلى الرقم التالي في المصفوفة ، تتحرك إلى اليمين.
  • في حالة عدم وجود المزيد من الأرقام في المصفوفة ، تُرجع العملية القيمة الإجمالية.

إصدار ES5 من أسلوب Reduce في JavaScript

إذا لم تكن قد استخدمت بناء جملة ES6 من قبل ، فلا تدع المثال أعلاه يخيفك. إنها بالضبط نفس الكتابة:

var euros = [29.76, 41.85, 46.5]; var sum = euros.reduce( function(total, amount){ return total + amount }); sum // 118.11

نستخدم constبدلاً من varونستبدل الكلمة functionبـ "سهم سمين" ( =>) بعد المعلمات ، ونحذف كلمة "عودة".

سأستخدم بناء جملة ES6 لبقية الأمثلة ، لأنها أكثر إيجازًا وتترك مساحة أقل للأخطاء.

إيجاد متوسط ​​باستخدام طريقة تقليل في JavaScript

بدلاً من تسجيل المجموع ، يمكنك قسمة المجموع على طول المصفوفة قبل إرجاع القيمة النهائية.

طريقة القيام بذلك هي الاستفادة من الحجج الأخرى في طريقة الاختزال. أول هذه الحجج هو الفهرس . يشبه إلى حد كبير حلقة for-loop ، يشير الفهرس إلى عدد مرات تكرار المخفض فوق المصفوفة. الوسيطة الأخيرة هي المصفوفة نفسها.

const euros = [29.76, 41.85, 46.5]; const average = euros.reduce((total, amount, index, array) => { total += amount; if( index === array.length-1) { return total/array.length; }else { return total; } }); average // 39.37

تعيين وتصفية كتخفيضات

إذا كان بإمكانك استخدام وظيفة التصغير لبصق متوسط ​​، فيمكنك استخدامها بالطريقة التي تريدها.

على سبيل المثال، هل يمكن أن يتضاعف المجموع، أو نصف كل رقم قبل إضافتها معا، أو استخدام تعليمة if داخل المخفض لإضافة أرقام فقط التي هي أكبر من 10. وجهة نظري هي أن خفض الطريقة في جافا سكريبت يمنحك مصغرة CodePen حيث يمكنك كتابة أي منطق تريده. فإنه سوف تكرار المنطق لكل المبلغ في مجموعة ثم إرجاع قيمة واحدة.

الشيء هو أنه ليس عليك دائمًا إرجاع قيمة واحدة. يمكنك تقليل المصفوفة إلى مصفوفة جديدة.

على سبيل المثال ، يتيح تقليل مجموعة من المبالغ إلى مصفوفة أخرى حيث يتم مضاعفة كل مبلغ. للقيام بذلك ، نحتاج إلى ضبط القيمة الأولية للمراكم لدينا على مصفوفة فارغة.

القيمة الأولية هي قيمة المعلمة الإجمالية عند بدء التخفيض. يمكنك تعيين القيمة الأولية عن طريق إضافة فاصلة متبوعة بالقيمة الأولية داخل الأقواس ولكن بعد الأقواس المتعرجة ( بخط غامق في المثال أدناه ).

const average = euros.reduce((total, amount, index, array) => { total += amount return total/array.length }, 0);

في الأمثلة السابقة ، كانت القيمة الأولية صفرًا لذا فقد حذفتها. بحذف القيمة الأولية ، فإن المجموع سوف يتحول إلى المقدار الأول في المصفوفة بشكل افتراضي.

من خلال ضبط القيمة الأولية على مصفوفة فارغة يمكننا بعد ذلك دفع كل مبلغ إلى المجموع . إذا أردنا تقليص مجموعة من القيم إلى مصفوفة أخرى حيث يتم مضاعفة كل قيمة ، نحتاج إلى دفع المبلغ * 2. ثم نعيد الإجمالي عندما لا يكون هناك المزيد من المبالغ لدفعها.

const euros = [29.76, 41.85, 46.5]; const doubled = euros.reduce((total, amount) => { total.push(amount * 2); return total; }, []); doubled // [59.52, 83.7, 93]

لقد أنشأنا مصفوفة جديدة حيث يتم مضاعفة كل مبلغ. يمكننا أيضًا تصفية الأرقام التي لا نريد مضاعفتها عن طريق إضافة عبارة if داخل المخفض.

const euro = [29.76, 41.85, 46.5]; const above30 = euro.reduce((total, amount) => { if (amount > 30) { total.push(amount); } return total; }, []); above30 // [ 41.85, 46.5 ]

هذه العمليات هي خريطة و مرشح أساليب إعادة كتابة كوسيلة من وسائل الحد.

بالنسبة لهذه الأمثلة ، سيكون من المنطقي استخدام خريطة أو عامل تصفية لأنهما أسهل في الاستخدام. تظهر فائدة استخدام تقليل عندما تريد التعيين والتصفية معًا ولديك الكثير من البيانات لتتجاوزها.

إذا قمت بتسلسل الخريطة والتصفية معًا ، فأنت تقوم بالعمل مرتين. تقوم بتصفية كل قيمة فردية ثم تقوم بتعيين القيم المتبقية. مع تقليل يمكنك التصفية ثم التعيين في مسار واحد.

استخدم الخريطة والتصفية ولكن عندما تبدأ في ربط الكثير من الطرق معًا ، فأنت تعلم الآن أنه من الأسرع تقليل البيانات بدلاً من ذلك.

إنشاء حساب باستخدام أسلوب التخفيض في JavaScript

استخدمه عندما : لديك مجموعة من العناصر وتريد معرفة عدد كل عنصر في المجموعة.

const fruitBasket = ['banana', 'cherry', 'orange', 'apple', 'cherry', 'orange', 'apple', 'banana', 'cherry', 'orange', 'fig' ]; const count = fruitBasket.reduce( (tally, fruit) =>  , {}) count // { banana: 2, cherry: 3, orange: 3, apple: 2, fig: 1 }

لحساب العناصر في مصفوفة ، يجب أن تكون القيمة الأولية كائنًا فارغًا ، وليست مصفوفة فارغة كما كانت في المثال الأخير.

نظرًا لأننا سنعيد كائنًا ، يمكننا الآن تخزين أزواج القيمة الرئيسية في المجموع.

fruitBasket.reduce( (tally, fruit) => { tally[fruit] = 1; return tally; }, {})

في المرور الأول ، نريد أن يكون اسم المفتاح الأول هو قيمتنا الحالية ونريد أن نمنحه القيمة 1.

هذا يعطينا كائنًا به كل الفاكهة كمفاتيح ، كل منها بقيمة 1. نريد زيادة كمية كل فاكهة إذا تكررت.

للقيام بذلك ، في الحلقة الثانية ، نتحقق مما إذا كان إجمالينا يحتوي على مفتاح بالفاكهة الحالية للمخفض. إذا لم يحدث ذلك فإننا ننشئه. إذا حدث ذلك ، فإننا نزيد المبلغ بمقدار واحد.

fruitBasket.reduce((tally, fruit) => { if (!tally[fruit]) { tally[fruit] = 1; } else { tally[fruit] = tally[fruit] + 1; } return tally; }, {});

لقد أعدت كتابة نفس المنطق بالضبط بطريقة أكثر إيجازًا في الأعلى.

تسوية مصفوفة من المصفوفات باستخدام أسلوب تقليل في JavaScript

يمكننا استخدام تقليل لتسوية المبالغ المتداخلة في مصفوفة واحدة.

نقوم بتعيين القيمة الأولية على مصفوفة فارغة ثم نربط القيمة الحالية بالمجموع.

const data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; const flat = data.reduce((total, amount) => { return total.concat(amount); }, []); flat // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

في كثير من الأحيان ، يتم دمج المعلومات بطرق أكثر تعقيدًا. على سبيل المثال ، لنفترض أننا نريد فقط كل الألوان في متغير البيانات أدناه.

const data = [ {a: 'happy', b: 'robin', c: ['blue','green']}, {a: 'tired', b: 'panther', c: ['green','black','orange','blue']}, {a: 'sad', b: 'goldfish', c: ['green','red']} ];

سنقوم بالمرور عبر كل كائن وسحب الألوان. نقوم بذلك عن طريق الإشارة إلى amount.c لكل كائن في المصفوفة. ثم نستخدم حلقة forEach لدفع كل قيمة في المصفوفة المتداخلة إلى المجموع.

const colors = data.reduce((total, amount) => { amount.c.forEach( color => { total.push(color); }) return total; }, []) colors //['blue','green','green','black','orange','blue','green','red']

إذا احتجنا فقط إلى رقم فريد ، فيمكننا التحقق لمعرفة العدد الإجمالي بالفعل قبل دفعه.

const uniqueColors = data.reduce((total, amount) => { amount.c.forEach( color => { if (total.indexOf(color) === -1){ total.push(color); } }); return total; }, []); uniqueColors // [ 'blue', 'red', 'green', 'black', 'orange']

الأنابيب مع تقليل

An interesting aspect of the reduce method in JavaScript is that you can reduce over functions as well as numbers and strings.

Let’s say we have a collection of simple mathematical functions. these functions allow us to increment, decrement, double and halve an amount.

function increment(input) { return input + 1;} function decrement(input) { return input — 1; } function double(input) { return input * 2; } function halve(input) { return input / 2; }

For whatever reason, we need to increment, then double, then decrement an amount.

You could write a function that takes an input, and returns (input + 1) * 2 -1. The problem is that we know we are going to need to increment the amount three times, then double it, then decrement it, and then halve it at some point in the future. We don’t want to have to rewrite our function every time so we going to use reduce to create a pipeline.

A pipeline is a term used for a list of functions that transform some initial value into a final value. Our pipeline will consist of our three functions in the order that we want to use them.

let pipeline = [increment, double, decrement];

Instead of reducing an array of values we reduce over our pipeline of functions. This works because we set the initial value as the amount we want to transform.

const result = pipeline.reduce(function(total, func) { return func(total); }, 1); result // 3

Because the pipeline is an array, it can be easily modified. If we want to decrement something three times, then double it, decrement it , and halve it then we just alter the pipeline.

var pipeline = [ increment, increment, increment, double, decrement, halve ];

The reduce function stays exactly the same.

Silly Mistakes to avoid

If you don’t pass in an initial value, reduce will assume the first item in your array is your initial value. This worked fine in the first few examples because we were adding up a list of numbers.

If you’re trying to tally up fruit, and you leave out the initial value then things get weird. Not entering an initial value is an easy mistake to make and one of the first things you should check when debugging.

Another common mistake is to forget to return the total. You must return something for the reduce function to work. Always double check and make sure that you’re actually returning the value you want.

Tools, Tips & References

  • Everything in this post came from a fantastic video series on egghead called Introducing Reduce. I give Mykola Bilokonsky full credit and I am grateful to him for everything I now know about using the Reduce Method In JavaScript​. I have tried to rewrite much of what he explains in my own words as an exercise to better understand each concept. Also, it’s easier for me to reference an article, as opposed to a video, when I need to remember how to do something.
  • The MDN Reduce documentation labels what I called a total the accumulator. It is important to know this because most people will refer to it as an accumulator if you read about it online. Some people call it prev as in previous value. It all refers to the same thing. I found it easier to think of a total when I was learning reduce.
  • If you would like to practice using reduce I recommend signing up to freeCodeCamp and completing as many of the intermediate algorithms as you can using reduce.
  • If the ‘const’ variables in the example snippets are new to you I wrote another article about ES6 variables and why you might want to use them.
  • I also wrote an article called The Trouble With Loops that explain how to use map() and filter() if the are new to you.

شكرا للقراءة! إذا كنت ترغب في أن يتم إعلامك عندما أكتب مقالًا جديدًا ، فيرجى إدخال بريدك الإلكتروني هنا.

وإذا أعجبك المقال ، فيرجى مشاركته على وسائل التواصل الاجتماعي حتى يتمكن الآخرون من العثور عليه.