foreach와지도 사이에 차이가 있습니까?


218

자, 이것은 특정 언어를 기반으로 한 질문보다 컴퓨터 과학 질문에 가깝지만 맵 작업과 foreach 작업 사이에 차이가 있습니까? 아니면 그들은 같은 것에 대해 단순히 다른 이름입니까?


흥미롭게도 Iterator[String]from을 가져 와서 scala.io.Source.fromFile("/home/me/file").getLines()적용 .foreach(s => ptintln(s))하면 제대로 인쇄되지만 곧 비워집니다. 동시에 적용 .map(ptintln(_))하면 비워지고 아무것도 인쇄되지 않습니다.
Ivan

답변:


294

다른.

foreach는 목록을 반복하고 부작용이있는 일부 작업을 각 목록 멤버에 적용합니다 (예 : 데이터베이스에 각 항목을 저장하는 등).

map은 목록을 반복하고 해당 목록의 각 구성원을 변환하며 변환 된 구성원과 동일한 크기의 다른 목록을 리턴합니다 (예 : 문자열 목록을 대문자로 변환).


고마워, 나는이 라인을 따라 무언가라고 생각했지만 확실하지 않았습니다!
로버트 굴드

19
:하지만 당신은 부작용이 응답 같은지도 기능 이고요에서 발생 할 수 stackoverflow.com/a/4927981/375688
TinyTimZamboni

6
언급해야 할 중요한 점 중 하나는 스칼라에서 특히 그렇습니다. 호출 하면 예상 변환 된 목록이 소환 될 때까지 기본 논리가 실행 map되지 않습니다 . 대조적으로 foreach의 작업은 즉시 계산됩니다.
bigT

124

그들 사이의 중요한 차이점은 map모든 결과를 컬렉션으로 모으고 foreach아무것도 반환하지 않는다는 것입니다. map함수를 사용하여 요소 컬렉션을 변환하려는 경우 일반적으로 사용되는 반면 foreach각 요소에 대한 작업을 간단히 실행합니다.


감사! 이제 차이점을 이해합니다. 그것은 꽤 오랫동안 나를 위해 흐릿했다
Robert Gould

또한 매우 중요합니다!
Мати Тернер

40

요컨대, 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또한 값을 반환하거나 반환하지 않을 수 있습니다. C ++ transform( map여기에 해당)에서는 반복자를 출력 컨테이너 (컬렉션)의 끝으로 반환합니다. Ruby에서의 반환 값은 map출력 시퀀스 (컬렉션)입니다. 따라서 알고리즘의 반환 값은 실제로 구현 세부 사항입니다. 그들의 효과는 그들이 돌아 오는 것일 수도 아닐 수도 있습니다.


.forEach()구현 하는 방법에 대한 예는 다음을 .map()참조하십시오. stackoverflow.com/a/39159854/1524693
Chinoto Vokro

32

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

그러나 다음 코드를 실행할 때 비틀기가 발생합니다.

여기에서는 map 및 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그렇지 않습니다. 따라서 map 메소드에 전달 된 콜백 함수 내에서 반환 된 배열을 조작 한 다음 반환 할 수 있습니다.

Array.prototype.forEach 주어진 배열을 통해서만 걸을 수 있으므로 배열을 걷는 동안 물건을 할 수 있습니다.


11

가장 '가시적 인'차이점은 map이 결과를 새로운 컬렉션에 축적하는 반면 foreach는 실행 자체에 대해서만 수행된다는 것입니다.

그러나 몇 가지 추가 가정이 있습니다. map의 '목적'은 새로운 값 목록이므로 실제로 실행 순서는 중요하지 않습니다. 실제로, 일부 실행 환경은 병렬 코드를 생성하거나 일부 값을 전혀 호출하지 않도록 반복 된 값을 호출하지 않거나 게으름을 피하기 위해 일부 메모리를 도입합니다.

반면에 foreach는 부작용을 위해 특별히 불려집니다. 따라서 순서가 중요하며 일반적으로 병렬화 할 수 없습니다.


11

짧은 대답 : map 그리고 forEach다릅니다. 또한 비공식적 map으로는의 엄격한 상위 집합입니다 forEach.

긴 대답 : 먼저 forEachand에 대한 한 줄 설명을 생각해 봅시다 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?

작업 1작업 2map 모두를 해결하는 데 사용할 수 있습니다 . 그러나 태스크 2 를 해결하는 데 사용할 수 없습니다 .forEach

에서 해결 한 당신은 단순히 교체하는 경우 forEachmap,이 솔루션은 여전히 유효합니다. 에서 해결 방법 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존재 하는가?

답은 효율성입니다. 배열을 다른 배열로 변환하지 않으려는 경우 왜 변환 된 배열을 계산해야합니까? 그것을 덤프 만? 당연히 아니지! 변환을 원하지 않으면 변환을 수행하지 않아야합니다.

따라서 map을 사용하여 작업 1 을 해결할 수는 있지만 아마 안됩니다. 각각에 대한 올바른 후보입니다.


원래 답변 :

내가 주로 @madlep의 대답에 동의하는 동안, 나는 그 점을 지적하고 싶습니다 map()A는 엄격한 슈퍼 세트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().

이것이 도움이 되었기를 바랍니다.


2015 년 11 월 10 일 수정 : 정교함이 추가되었습니다.


-1. 이것은 자바 스크립트에서만 유효합니다. 질문은 특별히 구현에 국한되지 않고 언어 불가지론과 컴퓨터 과학 개념에 대해 이야기합니다.
Javier

1
@Javier : Hmm .. JavaScript에 대한 답변에 대해 동의해야합니다. 그러나 스스로에게 물어보십시오 : 언어에 고유 한 map기능이 있지만 그렇지 않은 경우 forEach; map대신 대신 사용할 수 없었 forEach습니까? 반대로, 언어가 forEach있지만 언어가 없다면 자신의 언어 map를 구현해야합니다 map. forEach대신 대신 사용할 수 없습니다 map. 네가 어떻게 생각하는지 내게 말해 줘.
Sumukh Barve

3

다음은 목록을 사용하는 스칼라의 예입니다. map은 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

2

특히 자바 스크립트에 대해 이야기한다면 차이점은 map반복 함수 인 동안 루프 함수 forEach라는 것입니다.

사용 map이 목록의 각 구성원에 작업을 적용하고 결과를 원래 목록에 영향을주지 않고, 새로운 목록으로 돌아 가야합니다.

사용 forEach당신이하고 싶을 때 목록의 각 요소에 근거하여 무엇인가를. 예를 들어 페이지에 항목을 추가했을 수 있습니다. 기본적으로 "부작용"을 원할 때 유용합니다.

다른 차이점 : forEach(실제로 제어 흐름 함수이므로) 아무것도 반환하지 않으며 전달 된 함수는 색인과 전체 목록에 대한 참조를 얻는 반면 map은 새 목록을 반환하고 현재 요소에만 전달합니다.


0

ForEach는 RDD의 각 요소에 db 등을 쓰는 등의 기능을 되 돌리지 않고 적용하려고합니다.

그러나는 map()rdd 요소에 일부 함수를 적용하고 rdd를 반환합니다. 따라서 아래 방법을 실행하면 line3에서 실패하지 않지만 foreach를 적용한 후 rdd를 수집하는 동안 실패하고 오류가 발생합니다.

<모듈>의 파일 "<stdin>", 5 행

AttributeError : 'NoneType'개체에 'collect'특성이 없습니다.

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())
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.