هل هناك فرق بين foreach والخريطة؟
-
21-08-2019 - |
سؤال
حسنًا، هذا سؤال يتعلق بعلوم الكمبيوتر أكثر من كونه سؤالًا يعتمد على لغة معينة، ولكن هل هناك فرق بين عملية الخريطة وعملية foreach؟أم أنها مجرد أسماء مختلفة لنفس الشيء؟
المحلول
ومختلفة.
وبالتكرار foreach أكثر من قائمة ويطبق بعض العمليات مع الآثار الجانبية لكل عضو القائمة (مثل توفير كل واحد إلى قاعدة البيانات على سبيل المثال)
خريطة بالتكرار عبر قائمة، تحول كل عضو من أعضاء تلك القائمة، وإرجاع قائمة أخرى من نفس الحجم مع أعضاء تحولت (مثل تحويل قائمة السلاسل إلى أحرف كبيرة)
نصائح أخرى
والفرق المهم بينهما هو أن map
يتراكم كل النتائج في مجموعة، في حين foreach
يعود شيئا. يستخدم map
عادة عندما تريد تحويل مجموعة من العناصر ذات وظيفة، في حين foreach
ببساطة ينفذ هذا الإجراء لكل عنصر.
باختصار، foreach
هو تطبيق عملية على كل عنصر من مجموعة العناصر، في حين أن map
هو لتحويل مجموعة واحدة إلى أخرى.
هناك نوعان من الاختلافات الهامة بين foreach
و map
.
foreach
ليس لديه أي قيود مفاهيمية على العملية التي يطبقها، بخلاف ربما قبول عنصر كوسيطة.أي أن العملية قد لا تفعل شيئًا، أو قد يكون لها تأثير جانبي، أو قد تُرجع قيمة، أو قد لا تُرجع قيمة.الجميعforeach
ما يهمني هو التكرار على مجموعة من العناصر، وتطبيق العملية على كل عنصر.map
, ، من ناحية أخرى، لديه قيود على العملية:فهو يتوقع أن تقوم العملية بإرجاع عنصر، وربما تقبل أيضًا عنصرًا كوسيطة.الmap
تتكرر العملية على مجموعة من العناصر، وتطبق العملية على كل عنصر، وأخيرًا تخزن نتيجة كل استدعاء للعملية في مجموعة أخرى.وبعبارة أخرى،map
يتحول مجموعة إلى أخرى.foreach
يعمل مع مجموعة واحدة من العناصر.هذه هي مجموعة المدخلات.map
يعمل مع مجموعتين من العناصر:جمع المدخلات وجمع المخرجات.
ليس من الخطأ ربط الخوارزميتين:في الواقع، يمكنك عرض الاثنين بشكل هرمي، حيث map
هو تخصص foreach
.وهذا هو، يمكنك استخدام foreach
واطلب من العملية تحويل وسيطتها وإدراجها في مجموعة أخرى.لذلك foreach
الخوارزمية هي تجريد وتعميم لل map
خوارزمية.في الواقع، لأن foreach
ليس لديها أي قيود على عملها يمكننا أن نقول ذلك بأمان foreach
هي أبسط آلية تكرار متاحة، ويمكنها أن تفعل أي شيء يمكن أن تفعله الحلقة. map
, ، بالإضافة إلى خوارزميات أخرى أكثر تخصصًا، موجودة للتعبير:إذا كنت ترغب في تعيين (أو تحويل) مجموعة إلى أخرى، فإن نيتك تكون أكثر وضوحًا إذا كنت تستخدمها map
مما لو كنت تستخدم foreach
.
يمكننا توسيع هذه المناقشة بشكل أكبر، والنظر في copy
الخوارزمية:حلقة تقوم باستنساخ المجموعة.هذه الخوارزمية أيضًا هي أحد تخصصات foreach
خوارزمية.يمكنك تحديد عملية، بالنظر إلى عنصر ما، ستقوم بإدراج نفس العنصر في مجموعة أخرى.إذا كنت تستخدم foreach
بهذه العملية قمت في الواقع بتنفيذ copy
الخوارزمية، وإن كان ذلك مع انخفاض الوضوح أو التعبير أو الصراحة.دعونا نأخذ الأمر أبعد من ذلك:يمكننا القول بأنه map
هو تخصص copy
, ، في حد ذاته تخصص foreach
. map
يمكن يتغير أي من العناصر التي يتكرر عليها.لو map
لا يغير أيًا من العناصر فهو مجرد نسخ العناصر، واستخدامها ينسخ من شأنه أن يعبر عن النية بشكل أكثر وضوحا.
ال foreach
قد تحتوي الخوارزمية نفسها أو لا تحتوي على قيمة إرجاع، اعتمادًا على اللغة.في لغة C++، على سبيل المثال، foreach
إرجاع العملية التي تلقتها في الأصل.الفكرة هي أن العملية قد يكون لها حالة، وقد ترغب في إعادة هذه العملية لتفحص كيفية تطورها عبر العناصر. map
, ، أيضًا قد يُرجع أو لا يُرجع قيمة.في لغة سي++ transform
( ما يعادل map
هنا) يحدث لإرجاع مكرر إلى نهاية حاوية الإخراج (المجموعة).في روبي، قيمة الإرجاع map
هو تسلسل الإخراج (المجموعة).لذا، فإن القيمة المرجعة للخوارزميات هي في الحقيقة تفاصيل التنفيذ؛قد يكون تأثيرهم أو لا يكون ما يعودون إليه.
Array.protototype.map
طريقة & Array.protototype.forEach
كلاهما متشابهان تمامًا.
قم بتشغيل الكود التالي: http://labs.codecademy.com/bw1/6#:workspace
var arr = [1, 2, 3, 4, 5];
arr.map(function(val, ind, arr){
console.log("arr[" + ind + "]: " + Math.pow(val,2));
});
console.log();
arr.forEach(function(val, ind, arr){
console.log("arr[" + ind + "]: " + Math.pow(val,2));
});
أنها تعطي النتيجة نفسها بالضبط.
arr[0]: 1
arr[1]: 4
arr[2]: 9
arr[3]: 16
arr[4]: 25
arr[0]: 1
arr[1]: 4
arr[2]: 9
arr[3]: 16
arr[4]: 25
ولكن يأتي التطور عند تشغيل الكود التالي: -
لقد قمت هنا ببساطة بتعيين نتيجة القيمة المرجعة من الخريطة وطرق forEach.
var arr = [1, 2, 3, 4, 5];
var ar1 = arr.map(function(val, ind, arr){
console.log("arr[" + ind + "]: " + Math.pow(val,2));
return val;
});
console.log();
console.log(ar1);
console.log();
var ar2 = arr.forEach(function(val, ind, arr){
console.log("arr[" + ind + "]: " + Math.pow(val,2));
return val;
});
console.log();
console.log(ar2);
console.log();
الآن النتيجة شيء صعب!
arr[0]: 1
arr[1]: 4
arr[2]: 9
arr[3]: 16
arr[4]: 25
[ 1, 2, 3, 4, 5 ]
arr[0]: 1
arr[1]: 4
arr[2]: 9
arr[3]: 16
arr[4]: 25
undefined
خاتمة
Array.prototype.map
إرجاع مجموعة ولكن Array.prototype.forEach
لا.لذا يمكنك معالجة المصفوفة التي تم إرجاعها داخل وظيفة رد الاتصال التي تم تمريرها إلى طريقة الخريطة ثم إعادتها.
Array.prototype.forEach
يمشي فقط عبر المصفوفة المحددة حتى تتمكن من القيام بأشياءك أثناء المشي في المصفوفة.
ومعظم الفرق "مرئية" هو أن خريطة يتراكم النتيجة في المجموعة الجديدة، في حين يتم foreach فقط لتنفيذ نفسها.
ولكن هناك عددا من الافتراضات إضافية: منذ "الغرض" خريطة لائحة جديدة من القيم، فإنه لا يهم حقا أمر التنفيذ. في الواقع، بعض البيئات تنفيذ إنشاء رمز مواز، أو حتى إدخال بعض memoizing لتجنب يدعو إلى القيم المتكررة، أو lazyness، لتجنب استدعاء بعض على الإطلاق.
وforeach، من ناحية أخرى، ويسمى خصيصا لآثار جانبية. وبالتالي فإن النظام هو المهم، وعادة لا يمكن parallelised.
اجابة قصيرة: map
و forEach
مختلفة.أيضا، بشكل غير رسمي، map
هي مجموعة شاملة صارمة من forEach
.
اجابة طويلة: أولاً، دعونا نتوصل إلى وصف سطر واحد لـ forEach
و map
:
forEach
يتكرر على جميع العناصر، ويستدعي الوظيفة المتوفرة في كل منها.map
يتكرر على جميع العناصر، ويستدعي الوظيفة المتوفرة في كل منها، وينتج مصفوفة محولة عن طريق تذكر نتيجة كل استدعاء دالة.
في العديد من اللغات، forEach
غالبا ما يسمى فقط each
.تستخدم المناقشة التالية JavaScript كمرجع فقط.يمكن أن تكون حقا أي لغة أخرى.
الآن، دعونا نستخدم كل من هذه الوظائف.
استخدام forEach
:
مهمة 1: اكتب دالة printSquares
, ، والذي يقبل مجموعة من الأرقام arr
, ، ويطبع مربع كل عنصر فيه.
الحل 1:
var printSquares = function (arr) {
arr.forEach(function (n) {
console.log(n * n);
});
};
استخدام map
:
المهمة 2: اكتب دالة selfDot
, ، والذي يقبل مجموعة من الأرقام arr
, ، وتقوم بإرجاع مصفوفة حيث يكون كل عنصر هو مربع العنصر المقابل فيه arr
.
جانبا:هنا، بالمصطلحات العامية، نحاول تربيع مصفوفة الإدخال.بشكل رسمي، نحن نحاول حساب حاصل الضرب النقطي مع نفسه.
الحل 2:
var selfDot = function (arr) {
return arr.map(function (n) {
return n * n;
});
};
كيف هو map
مجموعة شاملة من forEach
?
يمكنك استخدام map
لحل كلتا المهمتين مهمة 1 و المهمة 2.ومع ذلك، لا يمكنك استخدام forEach
لحل المهمة 2.
في الحل 1, ، إذا قمت باستبدالها ببساطة forEach
بواسطة map
, ، سيظل الحل صالحًا.في الحل 2 ومع ذلك، استبدال map
بواسطة forEach
سوف يكسر حل عملك السابق.
تنفيذ forEach
من ناحية map
:
طريقة أخرى للإدراك map
التفوق هو التنفيذ forEach
من ناحية map
.وبما أننا مبرمجون جيدون، فلن ننغمس في تلوث مساحة الأسماء.سوف نتصل لدينا forEach
, ، فقط each
.
Array.prototype.each = function (func) {
this.map(func);
};
الآن، إذا كنت لا تحب prototype
هراء، هنا تذهب:
var each = function (arr, func) {
arr.map(func); // Or map(arr, func);
};
إذن أم..لماذا يفعل forEach
موجودة حتى؟
الجواب هو الكفاءةإذا لم تكن مهتمًا بتحويل مصفوفة إلى مصفوفة أخرى، فلماذا يجب عليك حساب المصفوفة المحولة؟فقط لتفريغها؟بالطبع لا!إذا كنت لا تريد التحول، فلا يجب أن تقوم بالتحول.
لذا، بينما يمكن استخدام الخريطة لحلها مهمة 1, ، ربما لا ينبغي ذلك.ولكل هو المرشح المناسب لذلك.
الإجابة الأصلية:
بينما أتفق إلى حد كبير مع إجابة @madlep، أود أن أشير إلى ذلك map()
هو مجموعة فائقة صارمة ل forEach()
.
نعم، map()
يستخدم عادةً لإنشاء مصفوفة جديدة.ومع ذلك، قد أيضًا يمكن استخدامها لتغيير المصفوفة الحالية.
هنا مثال:
var a = [0, 1, 2, 3, 4], b = null;
b = a.map(function (x) { a[x] = 'What!!'; return x*x; });
console.log(b); // logs [0, 1, 4, 9, 16]
console.log(a); // logs ["What!!", "What!!", "What!!", "What!!", "What!!"]
في المثال أعلاه، a
تم ضبطه بشكل مريح على هذا النحو a[i] === i
ل i < a.length
.وحتى مع ذلك، فإنه يدل على قوة map()
.
وهنا الوصف الرسمي ل map()
.لاحظ أن map()
قد يغير حتى المصفوفة التي يطلق عليها!يشيد map()
.
نأمل أن يكون هذا ساعد.
تم تحريره في 10 نوفمبر 2015:تمت إضافة تفصيل.
وهنا مثال في سكالا باستخدام القوائم: خريطة قائمة ترجع، foreach بإرجاع أي شيء.
def map(f: Int ⇒ Int): List[Int]
def foreach(f: Int ⇒ Unit): Unit
وهكذا خريطة ترجع القائمة الناتجة من تطبيق وظيفة و إلى كل عنصر القائمة:
scala> val list = List(1, 2, 3)
list: List[Int] = List(1, 2, 3)
scala> list map (x => x * 2)
res0: List[Int] = List(2, 4, 6)
وForeach ينطبق فقط و لكل عنصر:
scala> var sum = 0
sum: Int = 0
scala> list foreach (sum += _)
scala> sum
res2: Int = 6 // res1 is empty
إذا كنت تتحدث عن جافا سكريبت على وجه الخصوص، والفرق هو أن map
هي وظيفة حلقة في حين forEach
غير مكرر.
استخدم map
عندما تريد تطبيق عملية لكل عضو من أعضاء القائمة والحصول على النتائج يعود إلى قائمة جديدة، دون أن يؤثر ذلك على القائمة الأصلية.
استخدم forEach
عندما تريد قيام م> شيء على أساس كل عنصر من عناصر القائمة. هل يمكن أن يكون إضافة أشياء إلى الصفحة، على سبيل المثال. أساسا، انه لشيء رائع عندما تريد "الآثار الجانبية".
واختلافات أخرى: forEach
يعود أي شيء (لأنه هو حقا وظيفة التحكم في التدفق)، وظيفة مرت في يحصل المراجع للمؤشر واللائحة بأكملها، في حين خريطة ترجع قائمة جديدة ويمر فقط في العنصر الحالي.
وForEach يحاول تطبيق دالة مثل الكتابة إلى ديسيبل وغيرها على كل عنصر من عناصر RDD دون العودة أي شيء مرة أخرى.
ولكن map()
ينطبق بعض من وظيفة على عناصر من نشر الإشعاعات وإرجاع نشر الإشعاعات. وذلك عند تشغيل أسلوب أدناه فإنه لن تفشل في line3 لكن حين جمع نشر الإشعاعات بعد تطبيق foreach فسوف تفشل ورمي خطأ التي تقول
وملف "<ستدين>"، السطر 5، في <حدة>
وAttributeError: الكائن 'NoneType "لا يوجد لديه السمة' جمع '
اقتباس فقرة>nums = sc.parallelize([1,2,3,4,5,6,7,8,9,10])
num2 = nums.map(lambda x: x+2)
print ("num2",num2.collect())
num3 = nums.foreach(lambda x : x*x)
print ("num3",num3.collect())