ตกลงนี่เป็นคำถามเกี่ยวกับวิทยาศาสตร์คอมพิวเตอร์มากกว่าคำถามที่ใช้ภาษาใดภาษาหนึ่ง แต่มีความแตกต่างระหว่างการทำแผนที่และการดำเนินการ foreach หรือไม่? หรือพวกเขาเป็นชื่อที่แตกต่างกันสำหรับสิ่งเดียวกันหรือไม่
ตกลงนี่เป็นคำถามเกี่ยวกับวิทยาศาสตร์คอมพิวเตอร์มากกว่าคำถามที่ใช้ภาษาใดภาษาหนึ่ง แต่มีความแตกต่างระหว่างการทำแผนที่และการดำเนินการ foreach หรือไม่? หรือพวกเขาเป็นชื่อที่แตกต่างกันสำหรับสิ่งเดียวกันหรือไม่
คำตอบ:
ต่าง
foreach วนซ้ำทุกรายการและใช้การดำเนินการบางอย่างที่มีผลข้างเคียงกับสมาชิกแต่ละราย (เช่นบันทึกแต่ละรายการในฐานข้อมูลเป็นต้น)
แมปซ้ำทุกรายการเปลี่ยนสมาชิกแต่ละรายของรายการนั้นและส่งกลับรายการขนาดเดียวกันอีกครั้งด้วยสมาชิกที่ถูกเปลี่ยนรูป (เช่นการแปลงรายการสตริงเป็นตัวพิมพ์ใหญ่)
map
ไม่ได้ผลในการดำเนินการของตรรกะพื้นฐานของจนเมื่อคาดว่ารายการเปลี่ยนถูกเรียก ในทางตรงกันข้าม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 (หรือเปลี่ยน) หนึ่งในคอลเลกชันลงในอีกความตั้งใจของคุณเป็นที่ชัดเจนถ้าคุณใช้กว่าถ้าคุณใช้map
foreach
เราสามารถขยายการอภิปรายนี้เพิ่มเติมและพิจารณาcopy
อัลกอริทึม: ลูปที่โคลนโคลนคอลเลกชัน อัลกอริทึมนี้ก็เป็นความเชี่ยวชาญของforeach
อัลกอริทึม คุณสามารถกำหนดการดำเนินการที่กำหนดองค์ประกอบจะแทรกองค์ประกอบเดียวกันนั้นลงในคอลเลกชันอื่น หากคุณใช้foreach
กับการดำเนินการนั้นคุณจะได้ใช้copy
อัลกอริทึมแม้ว่าจะมีความชัดเจนลดลงแสดงออกหรือชัดเจน เราจะทำมันให้ดียิ่งขึ้น: เราสามารถพูดได้ว่าmap
เป็นความเชี่ยวชาญของตัวเองความเชี่ยวชาญของcopy
อาจเปลี่ยนองค์ประกอบใด ๆ ที่ทำซ้ำได้ หากไม่เปลี่ยนองค์ประกอบใด ๆ ก็เพียงแค่คัดลอกองค์ประกอบและการใช้งานforeach
map
map
คัดลอก จะแสดงเจตนาที่ชัดเจนยิ่งขึ้น
foreach
อัลกอริทึมตัวเองอาจหรือไม่อาจมีค่าตอบแทนขึ้นอยู่กับภาษา ใน C ++ ตัวอย่างเช่นforeach
ส่งคืนการดำเนินการที่ได้รับมาตั้งแต่แรก แนวคิดคือการดำเนินการอาจมีสถานะและคุณอาจต้องการให้การดำเนินการนั้นกลับไปตรวจสอบว่ามีการพัฒนาไปอย่างไรกับองค์ประกอบต่างๆ map
เช่นกันอาจจะหรืออาจจะไม่คืนค่า ใน C ++ transform
(เทียบเท่าสำหรับmap
ที่นี่) เกิดขึ้นเพื่อส่งกลับตัววนซ้ำไปยังจุดสิ้นสุดของคอนเทนเนอร์ส่งออก (คอลเลกชัน) ใน Ruby ค่าส่งคืนของ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 จะทำเพื่อการประมวลผลเท่านั้น
แต่มีข้อสมมติเพิ่มเติมสองสามข้อ: เนื่องจาก 'จุดประสงค์' ของแผนที่คือรายการค่าใหม่มันไม่สำคัญกับลำดับของการดำเนินการ ในความเป็นจริงบางสภาพแวดล้อมการดำเนินการสร้างรหัสขนานหรือแม้กระทั่งแนะนำการบันทึกความจำบางอย่างเพื่อหลีกเลี่ยงการเรียกค่าซ้ำหรือขี้เกียจเพื่อหลีกเลี่ยงการโทรบางอย่างเลย
foreach ตรงกันข้ามถูกเรียกโดยเฉพาะสำหรับผลข้างเคียง; ดังนั้นคำสั่งซื้อจึงมีความสำคัญและมักไม่สามารถเทียบเคียงได้
คำตอบสั้น ๆ : map
และforEach
แตกต่างกัน นอกจากนี้ทางการพูดmap
เป็น superset 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
เพื่อแก้ไขภารกิจที่ 22
ในโซลูชันที่ 1ถ้าคุณเพียงแค่แทนที่forEach
ด้วยmap
โซลูชันจะยังคงใช้ได้ อย่างไรก็ตามในโซลูชันที่ 2 การแทนที่map
ด้วยforEach
จะทำให้โซลูชันที่คุณใช้ก่อนหน้านี้ทำงานไม่สมบูรณ์
forEach
ในแง่ของmap
:วิธีการของการตระหนักถึงอีกmap
's ที่เหนือกว่าคือการใช้ในแง่ของ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 's คำตอบผมอยากจะชี้ให้เห็นว่า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 พ.ย. 2558: เพิ่มรายละเอียด
map
ฟังก์ชั่น แต่ไม่มีforEach
; คุณไม่สามารถใช้map
แทนได้forEach
ใช่ไหม ด้านพลิกถ้าภาษาที่มีforEach
แต่ไม่มีคุณต้องการมีการดำเนินการของคุณเองmap
map
คุณอาจจะไม่ได้เพียงแค่ใช้แทนforEach
map
บอกสิ่งที่คุณคิดว่า.
นี่คือตัวอย่างใน Scala ที่ใช้ list: map return list, foreach ไม่ส่งคืนอะไรเลย
def map(f: Int ⇒ Int): List[Int]
def foreach(f: Int ⇒ Unit): Unit
ดังนั้น map จะส่งคืนรายการที่เป็นผลมาจากการใช้ฟังก์ชัน f กับองค์ประกอบแต่ละรายการ:
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 ใช้ f กับแต่ละองค์ประกอบ:
scala> var sum = 0
sum: Int = 0
scala> list foreach (sum += _)
scala> sum
res2: Int = 6 // res1 is empty
หากคุณกำลังพูดถึง Javascript โดยเฉพาะความแตกต่างก็map
คือฟังก์ชั่นวนรอบในขณะที่forEach
เป็นตัววนซ้ำ
ใช้ map
เมื่อคุณต้องการใช้การดำเนินการกับสมาชิกแต่ละคนของรายการและรับผลลัพธ์กลับมาเป็นรายการใหม่โดยไม่กระทบกับรายการเดิม
ใช้forEach
เมื่อคุณต้องการทำอะไรบนพื้นฐานของแต่ละองค์ประกอบของรายการ คุณอาจกำลังเพิ่มสิ่งต่าง ๆ ลงในหน้าตัวอย่างเช่น โดยพื้นฐานแล้วมันยอดเยี่ยมเมื่อคุณต้องการ "ผลข้างเคียง"
ความแตกต่างอื่น ๆ : forEach
ไม่ส่งคืนสิ่งใด (เนื่องจากเป็นฟังก์ชันโฟลว์ควบคุม) และฟังก์ชัน pass-in ได้รับการอ้างอิงไปยังดัชนีและรายการทั้งหมดในขณะที่ map ส่งคืนรายการใหม่และส่งผ่านเฉพาะในองค์ประกอบปัจจุบันเท่านั้น
ForEach พยายามที่จะใช้ฟังก์ชั่นเช่นการเขียนไปยัง db ฯลฯ ในแต่ละองค์ประกอบของ RDD โดยไม่คืนสิ่งใดกลับมา
แต่การmap()
ใช้ฟังก์ชั่นบางอย่างมากกว่าองค์ประกอบของ rdd และส่งกลับ rdd ดังนั้นเมื่อคุณเรียกใช้วิธีการด้านล่างมันจะไม่ล้มเหลวที่ line3 แต่ในขณะที่รวบรวม rdd หลังจากใช้ foreach มันจะล้มเหลวและโยนข้อผิดพลาดที่ระบุว่า
ไฟล์ "<stdin>" บรรทัด 5 ใน <module>
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())
Iterator[String]
จากscala.io.Source.fromFile("/home/me/file").getLines()
และนำ.foreach(s => ptintln(s))
ไปใช้กับมันมันก็โอเค แต่ว่างเปล่าหลังจากนั้น ในเวลาเดียวกันถ้าฉันสมัคร.map(ptintln(_))
- มันว่างเปล่าและไม่มีอะไรพิมพ์