array_map, array_walk 및 array_filter의 차이점


373

정확히 어떤 것은 사이의 차이입니다 array_map, array_walk하고 array_filter. 설명서에서 볼 수있는 것은 제공된 배열에서 작업을 수행하기 위해 콜백 함수를 전달할 수 있다는 것입니다. 그러나 나는 그들 사이에 특별한 차이점을 찾지 못하는 것 같습니다.

그들은 같은 일을 수행합니까?
그것들을 서로 바꿔서 사용할 수 있습니까?

예시가 다른 경우 귀하의 도움에 감사드립니다.


이것은 array_reduce ()를 통한 명명 된 배열 처리를위한 멋진 방법입니다. array_map, array_walk 및 array_filter를 조사하는 경우 읽을 가치가 있습니다. stackoverflow.com/questions/11563119/…
랜스 클리블랜드

답변:


564
  • 값 변경 :
    • array_map가능한 동안 입력 배열 내부의 값을 변경할 수 없습니다 array_walk. 특히, array_map논쟁을 바꾸지 마십시오.
  • 어레이 키 액세스 :
  • 반환 값 :
    • array_map새 배열을 반환하고 array_walk만 반환합니다 true. 따라서 하나의 배열을 통과 한 결과 배열을 만들지 않으려면을 사용해야합니다 array_walk.
  • 여러 배열 반복
    • array_map또한 임의의 수의 배열을 수신 할 수 있으며 병렬로 반복 할 수 있지만 array_walk하나에서만 작동합니다.
  • 임의의 데이터를 콜백으로 전달 :
    • array_walk콜백에 전달할 추가 임의의 매개 변수를 수신 할 수 있습니다. 이것은 PHP 5.3 ( 익명 함수 가 도입 되었을 때) 이래로 대부분 관련이 없습니다 .
  • 반환 된 배열의 길이 :
    • 결과 배열은 array_map가장 큰 입력 배열과 길이가 같습니다. array_walk배열을 반환하지 않지만 동시에 원래 배열의 요소 수를 변경할 수 없습니다. array_filter필터링 함수에 따라 배열 요소의 하위 집합 만 선택합니다. 키를 유지합니다.

예:

<pre>
<?php

$origarray1 = array(2.4, 2.6, 3.5);
$origarray2 = array(2.4, 2.6, 3.5);

print_r(array_map('floor', $origarray1)); // $origarray1 stays the same

// changes $origarray2
array_walk($origarray2, function (&$v, $k) { $v = floor($v); }); 
print_r($origarray2);

// this is a more proper use of array_walk
array_walk($origarray1, function ($v, $k) { echo "$k => $v", "\n"; });

// array_map accepts several arrays
print_r(
    array_map(function ($a, $b) { return $a * $b; }, $origarray1, $origarray2)
);

// select only elements that are > 2.5
print_r(
    array_filter($origarray1, function ($a) { return $a > 2.5; })
);

?>
</pre>

결과:

Array
(
    [0] => 2
    [1] => 2
    [2] => 3
)
Array
(
    [0] => 2
    [1] => 2
    [2] => 3
)
0 => 2.4
1 => 2.6
2 => 3.5
Array
(
    [0] => 4.8
    [1] => 5.2
    [2] => 10.5
)
Array
(
    [1] => 2.6
    [2] => 3.5
)

3
PHP 매뉴얼에 "array_walk () : 배열의 값만 변경 될 수 있습니다";
feeela

10
"array_map은 배열 키로 작동 할 수 없습니다"이것은 사실이 아닙니다.array_map(callback($key, $value), array_keys($array), $array)
Jarek Jakubowski

12
여전히 배열의 키에 액세스하지 않고 키에서 생성 한 배열에 넣은 값을 초과합니다. 해결 방법이며 진술을 부정하지 않습니다.
inarilo

array_map은 값을 암시 적으로 변경하지 않지만 결과를 기본적으로 변경하는 것과 동일한 배열에 할당하여 동일한 배열 자체에서 작동하는 '역설적으로'array_walk는 값을 참조로 전달하지 않으면 값을 직접 변경하지 않습니다 (배열 walk는 원래 배열을 전달하는 익명 함수 use 절을 ​​통해 간접적으로 array_filter로 색인 / 요소를 제거 할 수 있지만 해결 방법입니다). 결론적으로, 값을 변경하거나 값이 참조에 의해 반환되거나 전달되는지의 차이는 덜 효과적이지만, 배열 보행은 여러 배열을 갖는 인덱스 및 배열 맵과 함께 작동합니다.
FentomX1

또한 배열 보행이 첫 번째 배열 매개 변수를 참조로 사용하더라도이를 변경하려면 콜백 항목 값을 참조로 전달해야합니다.
FentomX1

91

함수를 데이터 배열 에 매핑 한다는 아이디어는 함수형 프로그래밍에서 비롯됩니다. 배열의 각 요소에 대해 함수를 호출 array_map하는 foreach루프 로 생각해서는 안됩니다 (구현 방법 임에도 불구하고). 배열의 각 요소에 독립적으로 함수를 적용하는 것으로 생각해야합니다.

이론적으로 함수 매핑과 같은 것은 데이터에 적용되는 함수가 전역 상태가 아닌 데이터에만 영향을 미치기 때문에 병렬로 수행 될 수 있습니다. 왜냐하면 array_mapPHP에서는 그렇지 않더라도 항목에 함수를 적용하는 순서를 선택할 수 있기 때문 입니다.

array_walk반면에 데이터 배열을 처리하는 것과 정반대의 접근 방식입니다. 각 항목을 개별적으로 처리하는 대신 상태 ( &$userdata)를 사용 하고 foreach 루프와 같이 해당 위치에서 항목을 편집 할 수 있습니다. 항목이 $funcname적용될 때마다 프로그램의 전역 상태가 변경 될 수 있으므로 항목을 처리하는 올바른 단일 방법이 필요 합니다.

PHP 땅으로 돌아가서 데이터 반복을 더 잘 제어 할 수 있다는 점을 제외 array_map하고 array_walk는 거의 동일 array_walk하며 일반적으로 새로운 "변경된"배열을 반환하는 대신 데이터를 "변경"하는 데 사용됩니다.

array_filter실제로 array_walk(또는 array_reduce) 의 응용 프로그램이며 편의상 제공되는 것입니다.


5
"이론에서 데이터에 적용되는 함수가 전역 상태가 아닌 데이터에만 영향을 미치기 때문에 함수 매핑과 같은 작업을 병렬로 수행 할 수 있습니다."에 대한 두 번째 단락 통찰력에 +1 병렬 프로그래머에게는이 점을 명심해야합니다.
etherice

?를 array_filter()사용하여 구현 하는 방법을 설명 할 수 있습니까 array_walk()?
pfrenssen

40

설명서에서

bool array_walk (배열 & $ array, 콜백 $ funcname [, 혼합 $ userdata]) <-return bool

array_walk 는 배열과 함수를 받아서F 모든 요소 x를로 대체하여 수정합니다 F(x).

배열 array_map (콜백 $ callback, 배열 $ arr1 [, 배열 $ ...]) <-배열 반환

array_map 은 위치를 수정하는 대신 변환 된 요소가 포함 된 새 배열을 반환한다는 점을 제외하고 는 똑같은 작업 을 수행합니다.

배열 array_filter (배열 $ input [, 콜백 $ callback]) <-배열을 반환

F요소를 변환하는 대신 function을 가진 array_filterF(x) 는 true가 아닌 요소를 제거 합니다.


배열 값이 사라진 이유를 알 수 없습니다. 설명서를 살펴보면 array_walk비슷한 배열을 반환 한다고 가정 array_map하고 문제가 내 기능에 있다고 생각했습니다. 반환 유형이 부울이라는 것을 알기 전까지는 몰랐습니다.
Dylan Valade

22

다른 답변은 array_walk (in-place modified)와 array_map (return modified copy)의 차이점을 잘 보여줍니다. 그러나 그들은 실제로 array_map과 array_filter를 이해하는 조명 방법 인 array_reduce를 언급하지 않습니다.

array_reduce 함수는 다음과 같이 배열, 두 개의 인수 함수 및 '누산기'를 사용합니다.

array_reduce(array('a', 'b', 'c', 'd'),
             'my_function',
             $accumulator)

배열의 요소는 주어진 함수를 사용하여 한 번에 하나씩 누산기와 결합됩니다. 위의 호출 결과는 다음과 같습니다.

my_function(
  my_function(
    my_function(
      my_function(
        $accumulator,
        'a'),
      'b'),
    'c'),
  'd')

루프와 관련하여 생각하고 싶다면 다음과 같습니다 (배열 _reduce를 사용할 수없는 경우 실제로 이것을 폴백으로 사용했습니다).

function array_reduce($array, $function, $accumulator) {
  foreach ($array as $element) {
    $accumulator = $function($accumulator, $element);
  }
  return $accumulator;
}

이 루핑 버전을 사용하면 왜 세 번째 인수를 '누산기'라고 불렀는지 알 수 있습니다. 각 반복을 통해 결과를 누적하는 데 사용할 수 있습니다.

그렇다면 이것이 array_map 및 array_filter와 어떤 관련이 있습니까? 그것들은 둘 다 특정 종류의 array_reduce입니다. 다음과 같이 구현할 수 있습니다.

array_map($function, $array)    === array_reduce($array, $MAP,    array())
array_filter($array, $function) === array_reduce($array, $FILTER, array())

array_map과 array_filter가 다른 순서로 인수를 취한다는 사실을 무시하십시오. 그것은 PHP의 또 다른 단점입니다. 중요한 점은 오른쪽이 $ MAP 및 $ FILTER라는 함수를 제외하고는 동일하다는 것입니다. 그래서 그들은 어떻게 생겼습니까?

$MAP = function($accumulator, $element) {
  $accumulator[] = $function($element);
  return $accumulator;
};

$FILTER = function($accumulator, $element) {
  if ($function($element)) $accumulator[] = $element;
  return $accumulator;
};

보시다시피, 두 함수 모두 $ accumulator를 가져 와서 다시 반환합니다. 이 기능에는 두 가지 차이점이 있습니다.

  • $ MAP는 항상 $ accumulator에 추가되지만 $ FILTER는 $ function ($ element)가 TRUE 인 경우에만 추가합니다.
  • $ FILTER는 원래 요소를 추가하지만 $ MAP는 $ function ($ element)를 추가합니다.

이것은 쓸모없는 상식과는 거리가 멀다. 알고리즘을보다 효율적으로 만드는 데 사용할 수 있습니다!

우리는 종종 다음 두 가지 예제와 같은 코드를 볼 수 있습니다.

// Transform the valid inputs
array_map('transform', array_filter($inputs, 'valid'))

// Get all numeric IDs
array_filter(array_map('get_id', $inputs), 'is_numeric')

루프 대신 array_map 및 array_filter를 사용하면 이러한 예제가 매우 멋지게 보입니다. 그러나 첫 번째 호출 (맵 또는 필터)이 $ inputs를 통과하고 중간 배열을 작성하므로 $ inputs가 큰 경우 매우 비효율적 일 수 있습니다. 이 중간 배열은 두 번째 호출로 바로 전달되어 전체를 다시 통과 한 다음 중간 배열을 가비지 수집해야합니다.

array_map과 array_filter가 모두 array_reduce의 예라는 사실을 이용하여이 중간 배열을 제거 할 수 있습니다. 이들을 결합하면 각 예제에서 $ inputs를 한 번만 통과하면됩니다.

// Transform valid inputs
array_reduce($inputs,
             function($accumulator, $element) {
               if (valid($element)) $accumulator[] = transform($element);
               return $accumulator;
             },
             array())

// Get all numeric IDs
array_reduce($inputs,
             function($accumulator, $element) {
               $id = get_id($element);
               if (is_numeric($id)) $accumulator[] = $id;
               return $accumulator;
             },
             array())

참고 : array_map은 한 번에 하나의 배열 만 처리 할 수 ​​있고 array_filter는 기본 $ 함수로 "empty"를 사용하지 않기 때문에 위의 array_map 및 array_filter 구현은 PHP와 동일하게 작동하지 않습니다. 또한 키를 유지하지 않습니다.

그것들을 PHP처럼 동작시키는 것은 어렵지 않지만, 이러한 합병증으로 인해 핵심 아이디어를 찾기가 더 어려워 질 것이라고 생각했습니다.


1

다음 개정판은 PHP의 array_filer (), array_map () 및 array_walk ()를보다 명확하게 설명합니다.이 모두는 함수형 프로그래밍에서 시작되었습니다.

array_filter ()는 데이터를 필터링하여 다음과 같이 이전 배열의 원하는 항목 만 보유하는 새 배열을 생성합니다.

<?php
$array = array(1, "apples",2, "oranges",3, "plums");

$filtered = array_filter( $array, "ctype_alpha");
var_dump($filtered);
?>

여기에 라이브 코드

모든 숫자 값은 $ array에서 필터링되고 $ filtered는 과일 유형 만 남습니다.

array_map ()도 새로운 배열을 생성하지만 array_filter ()와 달리 결과 배열에는 $ filtered 입력의 모든 요소가 포함 되지만 다음과 같이 각 요소에 콜백을 적용하기 때문에 값이 변경됩니다.

<?php

$nu = array_map( "strtoupper", $filtered);
var_dump($nu);
?>

여기에 라이브 코드

이 경우 코드는 내장 strtoupper ()를 사용하여 콜백을 적용하지만 사용자 정의 함수도 또 다른 실행 가능한 옵션입니다. 콜백은 $ filtered의 모든 항목에 적용되므로 요소에 대문자 값이 포함 된 $ nu를 생성합니다.

다음 스 니펫에서 array walk ()는 $ nu를 통과하고 참조 연산자 '&'에 대해 각 요소를 변경합니다. 추가 배열을 만들지 않고 변경 사항이 발생합니다. 모든 요소의 값은 키, 범주 및 값을 지정하는보다 유익한 문자열로 변경됩니다.

<?php

$f = function(&$item,$key,$prefix) {
    $item = "$key: $prefix: $item";
}; 
array_walk($nu, $f,"fruit");
var_dump($nu);    
?>    

데모 보기

참고 : array_walk ()에 대한 콜백 함수는 array_walk ()에 의해 호출 될 때 요소의 값과 키를 자동으로 획득하는 두 개의 매개 변수를 사용합니다. (자세한 내용은 여기를 참조 하십시오 ).


1
기능 $lambda$callback기존 기능의 확장에 불과하므로 완전히 중복됩니다. 당신은 기본 기능 (이름)을 전달하여 같은 결과를 얻을 수 있습니다 : $filtered = array_filter($array, 'ctype_alpha');$nu = array_map('strtoupper', $filtered);
Warbo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.