Ok đây là một câu hỏi khoa học máy tính, hơn là một câu hỏi dựa trên một ngôn ngữ cụ thể, nhưng có sự khác biệt giữa một hoạt động bản đồ và một hoạt động foreach? Hay họ chỉ đơn giản là tên khác nhau cho cùng một điều?
Ok đây là một câu hỏi khoa học máy tính, hơn là một câu hỏi dựa trên một ngôn ngữ cụ thể, nhưng có sự khác biệt giữa một hoạt động bản đồ và một hoạt động foreach? Hay họ chỉ đơn giản là tên khác nhau cho cùng một điều?
Câu trả lời:
Khác nhau.
foreach lặp lại một danh sách và áp dụng một số thao tác với các tác dụng phụ cho từng thành viên trong danh sách (chẳng hạn như lưu từng cái vào cơ sở dữ liệu chẳng hạn)
ánh xạ lặp lại qua một danh sách, biến đổi từng thành viên của danh sách đó và trả về một danh sách khác có cùng kích thước với các thành viên được chuyển đổi (chẳng hạn như chuyển đổi danh sách các chuỗi thành chữ hoa)
map
nào không dẫn đến việc thực hiện của logic cơ bản của nó cho đến khi danh sách chuyển đổi dự kiến được triệu tập. Ngược lại, foreach
hoạt động của được tính toán ngay lập tức.
Sự khác biệt quan trọng giữa chúng là map
tích lũy tất cả các kết quả vào một bộ sưu tập, trong khi foreach
trả về không có gì. map
thường được sử dụng khi bạn muốn chuyển đổi một tập hợp các phần tử bằng một hàm, trong khi foreach
chỉ cần thực hiện một hành động cho mỗi phần tử.
Nói tóm lại, foreach
là để áp dụng một thao tác trên từng phần tử của một tập hợp các phần tử, trong khi đó map
là để chuyển đổi một bộ sưu tập thành một bộ sưu tập khác.
Có hai sự khác biệt đáng kể giữa foreach
và map
.
foreach
không có hạn chế về mặt khái niệm đối với hoạt động mà nó áp dụng, ngoài việc có thể chấp nhận một yếu tố làm đối số. Nghĩa là, hoạt động có thể không làm gì, có thể có tác dụng phụ, có thể trả về giá trị hoặc có thể không trả về giá trị. Tất cả foreach
quan tâm là lặp đi lặp lại một tập hợp các phần tử và áp dụng thao tác trên từng phần tử.
map
mặt khác, có một hạn chế đối với hoạt động: nó mong muốn hoạt động trả về một phần tử và có thể cũng chấp nhận một phần tử làm đối số. Các map
hoạt động lặp lại trên một tập hợp các yếu tố, áp dụng các hoạt động trên mỗi phần tử, và cuối cùng là lưu trữ các kết quả của mỗi lời gọi của hoạt động vào bộ sưu tập khác. Nói cách khác, map
biến một bộ sưu tập thành một bộ sưu tập khác.
foreach
làm việc với một bộ sưu tập các yếu tố Đây là bộ sưu tập đầu vào.
map
hoạt động với hai bộ sưu tập các phần tử: bộ sưu tập đầu vào và bộ sưu tập đầu ra.
Không có gì sai khi liên quan đến hai thuật toán: trên thực tế, bạn có thể xem hai thuật toán phân cấp, nơi map
chuyên môn hóa foreach
. Đó là, bạn có thể sử dụng foreach
và có thao tác chuyển đổi đối số của nó và chèn nó vào một bộ sưu tập khác. Vì vậy, foreach
thuật toán là một sự trừu tượng, khái quát hóa của map
thuật toán. Trong thực tế, vì foreach
không có hạn chế nào đối với hoạt động của nó, chúng ta có thể nói rằng đó foreach
là cơ chế lặp đơn giản nhất ngoài kia và nó có thể làm bất cứ điều gì mà một vòng lặp có thể làm. map
, cũng như các thuật toán chuyên dụng khác, có tính biểu cảm: nếu bạn muốn ánh xạ (hoặc biến đổi) bộ sưu tập này sang bộ sưu tập khác, ý định của bạn sẽ rõ ràng hơn nếu bạn sử dụng map
so với khi bạn sử dụng foreach
.
Chúng ta có thể mở rộng cuộc thảo luận này hơn nữa và xem xét copy
thuật toán: một vòng lặp nhân bản một bộ sưu tập. Thuật toán này cũng là một chuyên ngành của foreach
thuật toán. Bạn có thể định nghĩa một thao tác, được đưa ra một phần tử, sẽ chèn cùng phần tử đó vào một bộ sưu tập khác. Nếu bạn sử dụng foreach
với thao tác đó, bạn thực sự đã thực hiện copy
thuật toán, mặc dù giảm rõ ràng, biểu cảm hoặc nhân chứng. Chúng ta hãy đưa nó đi xa hơn: Chúng ta có thể nói rằng đó map
là một chuyên môn hóa copy
, bản thân nó là một chuyên môn hóa foreach
. map
có thể thay đổi bất kỳ yếu tố nào mà nó lặp đi lặp lại. Nếu map
không thay đổi bất kỳ phần tử nào thì nó chỉ sao chép các phần tử và sử dụng bản sao sẽ thể hiện ý định rõ ràng hơn.
Các foreach
thuật toán riêng của mình có thể hoặc không có thể có một giá trị trả về, tùy thuộc vào ngôn ngữ. Trong C ++, ví dụ, foreach
trả về thao tác mà nó nhận được ban đầu. Ý tưởng là hoạt động có thể có trạng thái và bạn có thể muốn hoạt động đó quay lại để kiểm tra xem nó đã phát triển như thế nào qua các yếu tố. map
cũng vậy, có thể hoặc không thể trả về giá trị. Trong C ++ transform
(tương đương với map
ở đây) tình cờ trả lại một iterator vào cuối bộ chứa đầu ra (bộ sưu tập). Trong Ruby, giá trị trả về map
là chuỗi đầu ra (bộ sưu tập). Vì vậy, giá trị trả về của các thuật toán thực sự là một chi tiết triển khai; tác dụng của chúng có thể hoặc không thể là những gì chúng trở lại.
.forEach()
có thể được sử dụng để thực hiện .map()
, hãy xem tại đây: stackoverflow.com/a/39159854/1524693
Array.protototype.map
phương pháp & Array.protototype.forEach
đều khá giống nhau.Chạy mã sau: 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));
});
Họ đưa ra kết quả chính xác.
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
Ở đây tôi chỉ cần gán kết quả của giá trị trả về từ các phương thức bản đồ và 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();
Bây giờ kết quả là một cái gì đó khó khăn!
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
trả về một mảng nhưng Array.prototype.forEach
không. Vì vậy, bạn có thể thao tác mảng trả về bên trong hàm gọi lại được truyền cho phương thức bản đồ và sau đó trả về nó.
Array.prototype.forEach
chỉ đi qua mảng đã cho để bạn có thể thực hiện công việc của mình trong khi đi bộ mảng.
sự khác biệt 'dễ thấy nhất' là bản đồ tích lũy kết quả trong một bộ sưu tập mới, trong khi việc tìm kiếm chỉ được thực hiện cho chính việc thực hiện.
nhưng có một vài giả định bổ sung: vì 'mục đích' của bản đồ là danh sách các giá trị mới, nên nó không thực sự quan trọng đối với thứ tự thực hiện. trong thực tế, một số môi trường thực thi tạo mã song song hoặc thậm chí giới thiệu một số ghi nhớ để tránh gọi các giá trị lặp lại hoặc lười biếng, để tránh gọi một số.
foreach, mặt khác, được gọi cụ thể cho các tác dụng phụ; do đó thứ tự là quan trọng và thường không thể song song.
Câu trả lời ngắn: map
và forEach
khác nhau. Ngoài ra, nói một cách không chính thức, map
là một superset nghiêm ngặt forEach
.
Câu trả lời dài: Đầu tiên, chúng ta hãy đưa ra một mô tả dòng forEach
và map
:
forEach
lặp lại trên tất cả các phần tử, gọi hàm được cung cấp trên mỗi phần tử.map
lặp lại trên tất cả các phần tử, gọi hàm được cung cấp trên mỗi phần tử và tạo ra một mảng được chuyển đổi bằng cách ghi nhớ kết quả của mỗi lệnh gọi hàm.Trong nhiều ngôn ngữ, forEach
thường được gọi là chỉ each
. Các cuộc thảo luận sau đây chỉ sử dụng JavaScript để tham khảo. Nó thực sự có thể là bất kỳ ngôn ngữ khác.
Bây giờ, hãy sử dụng từng chức năng này.
forEach
:Nhiệm vụ 1: Viết hàm printSquares
, chấp nhận một mảng các số arr
và in bình phương của mỗi phần tử trong đó.
Giải pháp 1:
var printSquares = function (arr) {
arr.forEach(function (n) {
console.log(n * n);
});
};
map
:Nhiệm vụ 2: Viết một hàm selfDot
, chấp nhận một mảng các số arr
và trả về một mảng trong đó mỗi phần tử là bình phương của phần tử tương ứng arr
.
Ngoài ra: Ở đây, về mặt tiếng lóng, chúng tôi đang cố gắng bình phương mảng đầu vào. Chính thức đặt, chúng tôi đang cố gắng tính toán sản phẩm chấm với chính nó.
Giải pháp 2:
var selfDot = function (arr) {
return arr.map(function (n) {
return n * n;
});
};
map
một superset của forEach
?Bạn có thể sử dụng map
để giải quyết cả hai nhiệm vụ, Nhiệm vụ 1 và Nhiệm vụ 2 . Tuy nhiên, bạn không thể sử dụng forEach
để giải quyết Nhiệm vụ 2 .
Trong Giải pháp 1 , nếu bạn chỉ cần thay thế forEach
bằng map
, giải pháp sẽ vẫn hợp lệ. Tuy nhiên, trong Giải pháp 2 , thay thế map
bằng forEach
sẽ phá vỡ giải pháp làm việc trước đây của bạn.
forEach
theo map
:Một cách khác để nhận ra map
tính ưu việt của nó là thực hiện forEach
theo nghĩa map
. Vì chúng tôi là những lập trình viên giỏi, chúng tôi sẽ không đắm chìm trong ô nhiễm không gian tên. Chúng tôi sẽ gọi cho chúng tôi forEach
, chỉ each
.
Array.prototype.each = function (func) {
this.map(func);
};
Bây giờ, nếu bạn không thích những prototype
điều vô nghĩa, ở đây bạn đi:
var each = function (arr, func) {
arr.map(func); // Or map(arr, func);
};
forEach
thậm chí còn tồn tại?Câu trả lời là hiệu quả. Nếu bạn không quan tâm đến việc chuyển đổi một mảng thành một mảng khác, tại sao bạn nên tính toán mảng đã chuyển đổi? Chỉ để đổ nó? Dĩ nhiên là không! Nếu bạn không muốn chuyển đổi, bạn không nên thực hiện chuyển đổi.
Vì vậy, trong khi bản đồ có thể được sử dụng để giải quyết Nhiệm vụ 1 , có lẽ không nên. Đối với mỗi là ứng cử viên phù hợp cho điều đó.
Mặc dù tôi rất đồng ý với câu trả lời của @madlep, tôi muốn chỉ ra rằng đó map()
là một siêu tập hợp nghiêm ngặt của forEach()
.
Có, map()
thường được sử dụng để tạo ra một mảng mới. Tuy nhiên, nó có thể cũng được sử dụng để thay đổi mảng hiện tại.
Đây là một ví dụ:
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!!"]
Trong ví dụ trên, a
được đặt thuận tiện sao a[i] === i
cho i < a.length
. Mặc dù vậy, nó thể hiện sức mạnh củamap()
.
Đây là mô tả chính thức củamap()
. Lưu ý rằng map()
thậm chí có thể thay đổi mảng mà nó được gọi! Kêumap()
.
Hy vọng điều này sẽ giúp.
Chỉnh sửa ngày 10 tháng 11 năm 2015: Thêm công phu.
map
chức năng riêng nhưng không forEach
; bạn không thể đơn giản là không sử dụng map
thay vì forEach
? Mặt khác, nếu một ngôn ngữ có forEach
nhưng không map
, bạn phải thực hiện ngôn ngữ của riêng bạn map
. Bạn không thể đơn giản sử dụng forEach
thay vì map
. Nói cho tôi biết bạn nghĩ gì.
Dưới đây là một ví dụ trong Scala sử dụng danh sách: danh sách trả về bản đồ, foreach không trả về gì.
def map(f: Int ⇒ Int): List[Int]
def foreach(f: Int ⇒ Unit): Unit
Vì vậy, bản đồ trả về danh sách kết quả từ việc áp dụng hàm f cho từng thành phần danh sách:
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 chỉ áp dụng f cho mỗi phần tử:
scala> var sum = 0
sum: Int = 0
scala> list foreach (sum += _)
scala> sum
res2: Int = 6 // res1 is empty
Nếu bạn đang nói về Javascript nói riêng, thì điểm khác biệt là map
chức năng lặp trong khi forEach
là trình lặp.
Sử dụng map
khi bạn muốn áp dụng một thao tác cho từng thành viên trong danh sách và lấy lại kết quả dưới dạng danh sách mới, mà không ảnh hưởng đến danh sách ban đầu.
Sử dụng forEach
khi bạn muốn làm một cái gì đó trên cơ sở từng yếu tố của danh sách. Bạn có thể thêm những thứ vào trang, ví dụ. Về cơ bản, thật tuyệt vời khi bạn muốn "tác dụng phụ".
Sự khác biệt khác: forEach
không trả về gì (vì đây thực sự là hàm điều khiển luồng) và hàm được truyền vào sẽ tham chiếu đến chỉ mục và toàn bộ danh sách, trong khi bản đồ trả về danh sách mới và chỉ truyền vào phần tử hiện tại.
ForEach cố gắng áp dụng một chức năng như ghi vào db, v.v. trên từng phần tử của RDD mà không trả lại bất cứ điều gì.
Nhưng map()
áp dụng một số chức năng trên các yếu tố của rdd và trả về rdd. Vì vậy, khi bạn chạy phương thức bên dưới, nó sẽ không bị lỗi ở dòng 3 nhưng trong khi thu thập rdd sau khi áp dụng foreach, nó sẽ thất bại và đưa ra một lỗi thông báo
Tệp "<stdin>", dòng 5, trong <mô-đun>
AttributionError: Đối tượng 'noneType' không có thuộc tính 'thu thập'
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]
từscala.io.Source.fromFile("/home/me/file").getLines()
và áp dụng.foreach(s => ptintln(s))
cho nó, nó được in ok nhưng sẽ trống ngay sau đó. Đồng thời nếu tôi áp dụng.map(ptintln(_))
cho nó - nó chỉ trống và không có gì được in.