سؤال

حسنًا، هذا سؤال يتعلق بعلوم الكمبيوتر أكثر من كونه سؤالًا يعتمد على لغة معينة، ولكن هل هناك فرق بين عملية الخريطة وعملية foreach؟أم أنها مجرد أسماء مختلفة لنفس الشيء؟

هل كانت مفيدة؟

المحلول

ومختلفة.

وبالتكرار foreach أكثر من قائمة ويطبق بعض العمليات مع الآثار الجانبية لكل عضو القائمة (مثل توفير كل واحد إلى قاعدة البيانات على سبيل المثال)

خريطة بالتكرار عبر قائمة، تحول كل عضو من أعضاء تلك القائمة، وإرجاع قائمة أخرى من نفس الحجم مع أعضاء تحولت (مثل تحويل قائمة السلاسل إلى أحرف كبيرة)

نصائح أخرى

والفرق المهم بينهما هو أن map يتراكم كل النتائج في مجموعة، في حين foreach يعود شيئا. يستخدم map عادة عندما تريد تحويل مجموعة من العناصر ذات وظيفة، في حين foreach ببساطة ينفذ هذا الإجراء لكل عنصر.

باختصار، foreach هو تطبيق عملية على كل عنصر من مجموعة العناصر، في حين أن map هو لتحويل مجموعة واحدة إلى أخرى.

هناك نوعان من الاختلافات الهامة بين foreach و map.

  1. foreach ليس لديه أي قيود مفاهيمية على العملية التي يطبقها، بخلاف ربما قبول عنصر كوسيطة.أي أن العملية قد لا تفعل شيئًا، أو قد يكون لها تأثير جانبي، أو قد تُرجع قيمة، أو قد لا تُرجع قيمة.الجميع foreach ما يهمني هو التكرار على مجموعة من العناصر، وتطبيق العملية على كل عنصر.

    map, ، من ناحية أخرى، لديه قيود على العملية:فهو يتوقع أن تقوم العملية بإرجاع عنصر، وربما تقبل أيضًا عنصرًا كوسيطة.ال map تتكرر العملية على مجموعة من العناصر، وتطبق العملية على كل عنصر، وأخيرًا تخزن نتيجة كل استدعاء للعملية في مجموعة أخرى.وبعبارة أخرى، map يتحول مجموعة إلى أخرى.

  2. 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())
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top