Array # each เทียบกับ Array # map


93
hash = { "d" => [11, 22], "f" => [33, 44, 55] }

# case 1
hash.map {|k,vs| vs.map {|v| "#{k}:#{v}"}}.join(",")
=> "d:11,d:22,f:33,f:44,f:55"

# case 2
hash.map {|k,vs| vs.each {|v| "#{k}:#{v}"}}.join(",")
=> "11,22,33,44,55"

เพียง แต่แตกต่างก็คือกรณีที่ 1 การใช้vs.mapกรณี 2 vs.eachใช้

เกิดอะไรขึ้นที่นี่?

คำตอบ:


175

Array#each เรียกใช้บล็อกที่กำหนดสำหรับแต่ละองค์ประกอบของอาร์เรย์จากนั้นส่งคืนอาร์เรย์เอง

Array#map ยังเรียกใช้บล็อกที่กำหนดสำหรับแต่ละองค์ประกอบของอาร์เรย์ แต่ส่งคืนอาร์เรย์ใหม่ที่มีค่าเป็นค่าส่งคืนของการวนซ้ำแต่ละครั้งของบล็อก

ตัวอย่าง: สมมติว่าคุณมีอาร์เรย์ที่กำหนดไว้ดังนี้:

arr = ["tokyo", "london", "rio"]

จากนั้นลองดำเนินการeach:

arr.each { |element| element.capitalize }
# => ["tokyo", "london", "rio"]

โปรดทราบว่าค่าที่ส่งคืนเป็นเพียงอาร์เรย์เดียวกัน โค้ดภายในeachบล็อกจะถูกเรียกใช้งาน แต่ค่าที่คำนวณจะไม่ถูกส่งกลับ และเนื่องจากโค้ดไม่มีผลข้างเคียงตัวอย่างนี้จึงไม่มีประโยชน์

ในทางตรงกันข้ามการเรียกmapเมธอดของอาร์เรย์จะส่งกลับอาร์เรย์ใหม่ที่มีองค์ประกอบเป็นค่าส่งกลับของแต่ละรอบของการดำเนินการmapบล็อก:

arr.map { |element| element.capitalize }
# => ["Tokyo", "London", "Rio"]

คำตอบที่สมบูรณ์แบบเพื่อทำความเข้าใจ เพียงแค่ .. คำเตือน: หากคุณใช้ค่าตอบแทนของฟังก์ชันแผนที่มากเกินไปคุณอาจเสียหน่วยความจำไปมาก
Imran Ahmad

33

ผลข้างเคียงที่จะเหมือนกันซึ่งจะเพิ่มความสับสนในการวิศวกรรมย้อนกลับของคุณ

ใช่ทั้งสองทำซ้ำบนอาร์เรย์ (จริงๆแล้วทับอะไรก็ตามที่ผสมในEnumerable ) แต่แผนที่จะส่งคืน Array ที่ประกอบด้วยผลลัพธ์ของบล็อกในขณะที่แต่ละรายการจะส่งคืน Array เดิม

ค่าตอบแทนของแต่ละเป็นเพียงอาร์เรย์เดิมและแทบจะไม่เคยใช้ในรหัสทับทิม แต่แผนที่เป็นหนึ่งในเครื่องมือการทำงานที่สำคัญที่สุด

สิ่งที่mapส่งคืนอาร์เรย์ซึ่งมีผลลัพธ์ของบล็อกหรือเมธอดตั้งชื่อที่ส่งผ่าน ตัวอย่างเช่น:

    2.2.3 :001 > [:how, :now, :brown, :cow].map &:to_s
 => ["how", "now", "brown", "cow"]

ในกรณีนี้ฉันไม่ได้ส่งผ่านบล็อก แต่เพียงแค่ a Symbolอย่างไรก็ตามclass Symbolวัตถุมีto_procวิธีการที่จะส่งผลให้:

[:how.to_s, :now.to_s, ...]

BTW คุณอาจจะมีช่วงเวลาที่ยากในการหาเอกสารเพราะแผนที่เป็นวิธีการในEnumerableในขณะที่แต่ละ (วิธีหนึ่งที่จำเป็นโดยEnumerableโมดูล) เป็นวิธีการในอาร์เรย์

หมายเหตุ: การใช้งานแผนที่จะขึ้นอยู่กับแต่ละข้อ


13

นี่คือตัวอย่างสั้น ๆ เกี่ยวกับความแตกต่างของแผนที่จากแต่ละแผนที่

a = ["a", "b", "c"];
#Array.map
p a.map {|item| "map_" + item}
#prints ["map_a", "map_b", "map_c"]

#Array.each
p a.each {|item| "map_" + item}
#prints ["a", "b", "c"]

คุณจะเห็นว่าผลตอบแทนแผนที่["map_a", "map_b", "map_c"]ในขณะที่แต่ละเพียง iterates ["a", "b", "c"]แต่กลับอาร์เรย์เดิม:

ดังนั้นแต่ละรายการจึงใช้สำหรับการประมวลผลอาร์เรย์และแผนที่จะใช้เพื่อทำบางสิ่งกับอาร์เรย์ที่ประมวลผล


4

.each ส่งคืนอาร์เรย์เดียวกันกับที่คุณให้ไว้ในตอนแรก:

[1,2,3].each { |i| i + 1 }
#=> [1,2,3]

.map ส่งคืน Array ใหม่จากผลลัพธ์ของการเรียกแต่ละบล็อก:

[1,2,3].map { |i| i + 1 }
#=> [2,3,4]

1

Array # แต่ละวิธีจะส่งคืนอาร์เรย์เดียวกัน

a = [1,2,3,4,5]
a.object_id #70284994490700

b = a.each {|n| n + 2}
p b #[1,2,3,4,5]
b.object_id #70284994490700 <<--- it's the same as a

Array # map method ส่งคืนอาร์เรย์ใหม่

c = [1,2,3,4,5]
c.object_id #70219117705860

d = c.map {|n| n + 2}
p d #[3,4,5,6,7]
d.object_id #70284994343620  <<---- it's different than c

0

เมื่อคุณใช้แมปกับแฮชมันจะโยนแฮชไปยังอาร์เรย์โดยปริยายดังนั้นคุณจึงมี

[["d", [11, 22]], ["f", [33, 44, 55]]]

เทียบกับแต่ละ {... } ให้คุณย้อนกลับการประเมินผลล่าสุดเท่านั้นซึ่งก็คือ [11, 22] สำหรับ ["d", [11, 22]] และ [33, 44, 55] สำหรับ ["f", [ 33, 44, 55]]. ดังนั้นก่อนการเข้าร่วมครั้งสุดท้ายคุณมี

[[11, 22], [33, 44, 55]]

0

คุณยังสามารถใช้mapกับปังmap!ที่เปลี่ยนอาร์เรย์ต้นทางได้


นี่ไม่ใช่คำตอบสำหรับคำถาม คำถามเกี่ยวกับความแตกต่างระหว่างeachซึ่งดำเนินการบล็อกที่กำหนดและส่งคืนอาร์เรย์เดิม และmapซึ่งส่งคืนอาร์เรย์พร้อมผลลัพธ์ของการเรียกใช้บล็อกเป็นค่า
Sampson Crowley
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.