PHP에서 다차원 배열을 단순 배열로 "평탄화"하는 방법은 무엇입니까?


83

아마도 초보 질문 일 수 있지만 이미 문서화를 더 오래 진행하고 있으며 해결책을 찾을 수 없습니다. 나는 각 차원에 대해 내파를 사용할 수 있다고 생각한 다음 그 문자열을 다시 결합하여 str_split새로운 간단한 배열을 만들 수 있습니다. 그러나 조인 패턴이 값에도 없는지 결코 알 수 없으므로 str_split원래 값 을 수행 한 후에 는 깨질 수 있습니다.

combine($array1, $array2)다차원 배열 내부의 배열 과 같은 것이 있습니까?


이 링크를 확인하십시오 . stackoverflow.com/questions/14951811/…
Prasanth Bendra

1
더 나은 답변이있는 또 다른 좋은 참조 질문 : 다차원 배열을 평면화하는 방법?
hakre

답변:


42

사용하다 array_walk_recursive

<?php

$aNonFlat = array(
    1,
    2,
    array(
        3,
        4,
        5,
        array(
            6,
            7
        ),
        8,
        9,
    ),
    10,
    11
);

$objTmp = (object) array('aFlat' => array());

array_walk_recursive($aNonFlat, create_function('&$v, $k, &$t', '$t->aFlat[] = $v;'), $objTmp);

var_dump($objTmp->aFlat);

/*
array(11) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [3]=>
  int(4)
  [4]=>
  int(5)
  [5]=>
  int(6)
  [6]=>
  int(7)
  [7]=>
  int(8)
  [8]=>
  int(9)
  [9]=>
  int(10)
  [10]=>
  int(11)
}
*/

?>

PHP 5.5.9-1ubuntu4.24 (cli)로 테스트 됨 (빌드 : 2018 년 3 월 16 일 12:32:06)


참조로 (감가 상각 된) 호출 시간을 사용하지 않는 한 이것이 작동하지 않는 이유를 아는 사람이 있습니까? 즉, array_walk_recursive ($ array, create_function ( '& $ v, $ k, & $ t', '$ t [] = $ v;'), & $ flattened); 함수 정의가 참조에 의한 전달로 올바르게 정의되었습니다. 그러나 호출 시간 동안 참조로 전달하지 않으면 작동하지 않습니다.
jskulski

2
@jskilski 객체 ( $objTmp이 예에서)는 자동으로 참조로 전달됩니다. 배열은 아닙니다. 대신 익명 함수 ( php.net/manual/en/functions.anonymous.php )를 사용해보십시오 create_function.
dave1010 2011-08-31

1
- 때문에 array_walk_recursive의 버그 PHP 5.3.3에서이 나던 작업 bugs.php.net/bug.php?id=52719
crazyphoton

1
@crazyphoton 꼬임은 말한다This bug has been fixed in SVN.
뤽 M

10
이 답변은 왜 사용을 언급 array_values()합니까? 나는 대답에 관련된 그 기능의 사용을 전혀 볼 수 없습니다.
thomasrutter

134
$array  = your array

$result = call_user_func_array('array_merge', $array);

echo "<pre>";
print_r($result);

참조 : http://php.net/manual/en/function.call-user-func-array.php

다음은 또 다른 솔루션입니다 (다차원 배열로 작동).

function array_flatten($array) {

   $return = array();
   foreach ($array as $key => $value) {
       if (is_array($value)){ $return = array_merge($return, array_flatten($value));}
       else {$return[$key] = $value;}
   }
   return $return;

}

$array  = Your array

$result = array_flatten($array);

echo "<pre>";
print_r($result);

이 답변은 허용되는 답변보다 훨씬 빠릅니다.
Roham Rafii

8
php5.3부터 이제 splat 연산자를 사용할 수 있습니다 : $result = array_merge(...$array); php.net/manual/en/…
Redzarf

1
첫 번째 대답은 다차원 배열에서 작동하지 않습니다. 3v4l.org/tY8vD
dearsina

55

이것은 한 줄이며 사용하기 매우 쉽습니다.

$result = array();
array_walk_recursive($original_array,function($v) use (&$result){ $result[] = $v; });

익명의 기능 / 폐쇄 내에서 이해하기 매우 쉽습니다. $v귀하의 $original_array.


5
이것은 2 레벨 배열에서 나를 위해 일한 유일한 것입니다.
Ciprian Tepes

18
// $array = your multidimensional array

$flat_array = array();

foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $k=>$v){

$flat_array[$k] = $v;

}

또한 문서화 됨 : http://www.phpro.org/examples/Flatten-Array.html


2
참고 : 원시 배열에만 사용하십시오. "RecursiveArrayIterator는 모든 객체를 자식이있는 것으로 취급하고 재귀를 시도합니다." php.net/manual/en/class.recursivearrayiterator.php#106519
ReactiveRaven

@hakre : +1 동의 : iterator_to_array()이 답변에 추가 하면 foreach루프 가 필요하지 않습니다 . 간단한 한 줄짜리 기능이 될 수 있습니다. (다소 긴 한 줄 임에도 불구하고)
SDC

2
나는 이것이 오래되었지만 여전히 유용하다는 것을 알고 있지만 $ k는 카운터와 같은 독특한 것으로 대체되어야합니다. $ k 만 사용하면 내부 배열의 이름이 기본 배열과 동일하면 요소가 제거됩니다.
Austin Best

12

특별히 한 수준 이상으로 가지 않는 배열이있는 경우 (일반적인 사용 사례) array_merge및 표시 연산자를 사용하면됩니다.

<?php

$notFlat = [[1,2],[3,4]];
$flat = array_merge(...$notFlat);
var_dump($flat);

산출:

array(4) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [3]=>
  int(4)
}

splat 연산자는 배열의 배열을에 대한 인수로 배열 목록으로 효과적으로 변경합니다 array_merge.


이것은 나에게 가장 좋은 대답 인 것 같습니다. 그것은 문자열 키가 작동하지 않습니다,하지만 쉽게 할 수정할 수 있도록 :$flat = array_merge( array_keys( $notFlat ), ...array_values( $notFlat ) );
이안 던

6

PHP 7에서는 생성기 및 생성기 위임 ( yield from)을 사용하여 배열을 평면화 할 수 있습니다.

function array_flatten_iterator (array $array) {
    foreach ($array as $value) {
        if (is_array($value)) {
            yield from array_flatten_iterator($value);
        } else {
            yield $value;
        }
    }
}

function array_flatten (array $array) {
    return iterator_to_array(array_flatten_iterator($array), false);
}

예:

$array = [
    1,
    2,
    [
        3,
        4,
        5,
        [
            6,
            7
        ],
        8,
        9,
    ],
    10,
    11,
];    

var_dump(array_flatten($array));

http://3v4l.org/RU30W


5
function flatten_array($array, $preserve_keys = 0, &$out = array()) {
    # Flatten a multidimensional array to one dimension, optionally preserving keys.
    #
    # $array - the array to flatten
    # $preserve_keys - 0 (default) to not preserve keys, 1 to preserve string keys only, 2 to preserve all keys
    # $out - internal use argument for recursion
    foreach($array as $key => $child)
        if(is_array($child))
            $out = flatten_array($child, $preserve_keys, $out);
        elseif($preserve_keys + is_string($key) > 1)
            $out[$key] = $child;
        else
            $out[] = $child;
    return $out;
}

죄송하지만 제대로 다차원 배열을 처리하지 않는 것 - 데모
알바로 곤잘레스

5

PHP의 사용자 의견 (간체)과 여기에있는 또 다른 방법 :

function array_flatten_recursive($array) { 
   if (!$array) return false;
   $flat = array();
   $RII = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
   foreach ($RII as $value) $flat[] = $value;
   return $flat;
}

이 방법의 가장 큰 장점은 평면화하는 동안 필요한 경우 재귀의 깊이를 추적한다는 것입니다.
그러면 다음이 출력됩니다.

$array = array( 
    'A' => array('B' => array( 1, 2, 3)), 
    'C' => array(4, 5) 
); 
print_r(array_flatten_recursive($array)); 

#Returns: 
Array ( 
    [0] => 1 
    [1] => 2 
    [2] => 3 
    [3] => 4 
    [4] => 5 
)

3
참고 : 원시 배열에만 사용하십시오. "RecursiveArrayIterator는 모든 객체를 자식이있는 것으로 취급하고 재귀를 시도합니다." php.net/manual/en/class.recursivearrayiterator.php#106519
ReactiveRaven

4

비재 귀적 솔루션 (순서 파괴) :

function flatten($ar) {
    $toflat = array($ar);
    $res = array();

    while (($r = array_shift($toflat)) !== NULL) {
        foreach ($r as $v) {
            if (is_array($v)) {
                $toflat[] = $v;
            } else {
                $res[] = $v;
            }
        }
    }

    return $res;
}

4

PHP> = 5.3에서 Luc M의 답변 (첫 번째 답변)에 따라 다음과 같은 클로저를 사용할 수 있습니다.

array_walk_recursive($aNonFlat, function(&$v, $k, &$t){$t->aFlat[] = $v;}, $objTmp);

create_function ()을 사용할 때와 같이 함수의 코드를 따옴표로 묶을 필요가 없기 때문에 이것을 좋아합니다.


1
익명 함수를 사용하는 경우, 당신은뿐만 아니라이보다 직접적으로 오히려 촬영 된 폐쇄 변수를 사용할 수있는 objTemp것들
user102008

1
이 충돌을 일으키는 PHP5.3.3에서 버그가 있습니다 - bugs.php.net/bug.php?id=52719
crazyphoton은

2

고차 함수 사용 (참고 : PHP 5.3에 등장한 인라인 익명 함수를 사용하고 있습니다 ) :

function array_flatten($array) {
    return array_reduce(
        $array,
        function($prev, $element) {
            if (!is_array($element))
                $prev[] = $element;
            else
                $prev = array_merge($prev, array_flatten($element));
            return $prev;
        },
        array()
    );
}

1

chaos가 제출 한 이전 예제 함수를 기반으로 한 새로운 접근 방식으로 다중 배열에서 문자열 키를 덮어 쓰는 버그를 수정합니다.

# Flatten a multidimensional array to one dimension, optionally preserving keys.
# $array - the array to flatten
# $preserve_keys - 0 (default) to not preserve keys, 1 to preserve string keys only, 2 to preserve all keys
# $out - internal use argument for recursion

function flatten_array($array, $preserve_keys = 2, &$out = array(), &$last_subarray_found) 
{
        foreach($array as $key => $child)
        {
            if(is_array($child))
            {
                $last_subarray_found = $key;
                $out = flatten_array($child, $preserve_keys, $out, $last_subarray_found);
            }
            elseif($preserve_keys + is_string($key) > 1)
            {
                if ($last_subarray_found)
                {
                    $sfinal_key_value = $last_subarray_found . "_" . $key;
                }
                else
                {
                    $sfinal_key_value = $key;
                }
                $out[$sfinal_key_value] = $child;
            }
            else
            {
                $out[] = $child;
            }
        }

        return $out;
}

Example:
$newarraytest = array();
$last_subarray_found = "";
$this->flatten_array($array, 2, $newarraytest, $last_subarray_found);

1
/*consider $mArray as multidimensional array and $sArray as single dimensional array
this code will ignore the parent array
*/

function flatten_array2($mArray) {
    $sArray = array();

    foreach ($mArray as $row) {
        if ( !(is_array($row)) ) {
            if($sArray[] = $row){
            }
        } else {
            $sArray = array_merge($sArray,flatten_array2($row));
        }
    }
    return $sArray;
}

1

당신은 이것을 시도 할 수 있습니다 :

function flat_an_array($a)
{
    foreach($a as $i)
    {
        if(is_array($i)) 
        {
            if($na) $na = array_merge($na,flat_an_array($i));
            else $na = flat_an_array($i);
        }
        else $na[] = $i;
    }
    return $na;
}

1

배열 키를 잃어도 괜찮다면 다음과 같이 array_values ​​()를 활용하는 콜백으로 재귀 적 클로저를 사용하여 다차원 배열을 평면화하여이 콜백이 array_walk ()의 ​​매개 변수인지 확인하십시오.

<?php  

$array = [1,2,3,[5,6,7]];
$nu_array = null;
$callback = function ( $item ) use(&$callback, &$nu_array) {
    if (!is_array($item)) {
    $nu_array[] = $item;
    }
    else
    if ( is_array( $item ) ) {
     foreach( array_values($item) as $v) {
         if ( !(is_array($v))) {
             $nu_array[] = $v;
         }
         else
         { 
             $callback( $v );
         continue;
         }    
     }
    }
};

array_walk($array, $callback);
print_r($nu_array);

이전 예제의 한 가지 단점은 단순화 된 콜백과 함께 array_walk_recursive ()를 사용하는 다음 솔루션보다 훨씬 더 많은 코드를 작성해야한다는 것입니다.

<?php  

$array = [1,2,3,[5,6,7]];

$nu_array = [];
array_walk_recursive($array, function ( $item ) use(&$nu_array )
                     {
                         $nu_array[] = $item;
                     }
);
print_r($nu_array);

보다 라이브 코드

이 예제는 다차원 배열에서 값을 추출하는 방법에 대한 세부 정보를 숨기는 이전 예제보다 선호됩니다. 확실히 반복이 발생하지만 재귀 또는 제어 구조가 수반되는지 여부에 관계없이 array.c 를 숙독해야 알 수 있습니다 . 함수형 프로그래밍은 결과를 얻는 것보다 입력과 출력에 초점을 맞추기 때문에, 분명히 고용주가 그러한 질문을 제기 할 때까지이면에서 반복이 어떻게 발생하는지에 대해 걱정할 필요가 없습니다.


1

다단계 배열을 하나로 변환하는 간단한 방법을 찾았습니다. 배열을 URL 문자열로 변환하는 "http_build_query"함수를 사용합니다. 그런 다음 explode로 문자열을 분할하고 값을 디코딩합니다.

다음은 샘플입니다.

$converted = http_build_query($data);
$rows = explode('&', $converted);
$output = array();
foreach($rows AS $k => $v){
   list($kk, $vv) = explode('=', $v);
   $output[ urldecode($kk) ] =  urldecode($vv);
}
return $output;

1

necrobumping에 대해 죄송하지만 제공된 답변 중 어느 것도 "다차원 배열 병합"으로 직관적으로 이해 한 작업을 수행하지 않았습니다. 즉이 경우 :

[
  'a' => [
    'b' => 'value',
  ]
]

제공된 모든 솔루션은이를으로 평평하게 ['value']만들지 만 키와 깊이에 대한 정보가 손실되고 다른 곳에 'b'키가 있으면 덮어 씁니다.

다음과 같은 결과를 얻고 싶었습니다.

[
  'a_b' => 'value',
]

array_walk_recursive 현재 반복되는 키에 대한 정보를 전달하지 않으므로 일반 재귀로 수행했습니다.

function flatten($array, $prefix = '') {
    $return = [];
    foreach ($array as $key => $value) {
        if (is_array($value)) {
            $return = array_merge($return, flatten($value, $prefix . $key . '_'));
        } else {
            $return[$prefix . $key] = $value;
        }
    }
    return $return;
}

$ prefix 및 '_'구분 기호를 원하는대로 수정하십시오.

여기 놀이터 : https://3v4l.org/0B8hf



0

간단한 접근 .. 재귀를 통해보기 ..

<?php

function flatten_array($simple){
static $outputs=array();
foreach ( $simple as $value)
{
if(is_array($value)){
    flatten_array($value);
}
else{
    $outputs[]=$value;
}

}
return $outputs;
}

$eg=['s'=>['p','n'=>['t']]];
$out=flatten_array($eg);
print_r($out);

?>

static이 작업에 잠재적으로 나쁜 아이디어를 사용 하는 이유는 무엇 입니까? 의도하지 않은 데이터 보존. 이것은 프로그래머가이 동작을 모르거나 기대하지 않는다면 놀라움으로 확실히 잡을 것입니다. 이 데모를보십시오 .
mickmackusa

"코드 전용"답변을 게시했습니다. OP 및 미래 연구원을 교육하지 못하기 때문에 StackOverflow에서 가치가 낮습니다. 답변이 작동하는 방식과 이전 답변보다 더 나은 아이디어라고 생각하는 이유를 포함하여 잠시 시간을내어이 답변을 개선하십시오.
mickmackusa

0

누군가가 유용하다고 생각할 수도 있고, 어떤 차원에서 배열을 평평하게하는 데 문제가있었습니다. 예를 들어 다음과 같은 배열이있는 경우 마지막 차원이라고 부를 것입니다.

array (
  'germany' => 
  array (
    'cars' => 
    array (
      'bmw' => 
      array (
        0 => 'm4',
        1 => 'x3',
        2 => 'x8',
      ),
    ),
  ),
  'france' => 
  array (
    'cars' => 
    array (
      'peugeot' => 
      array (
        0 => '206',
        1 => '3008',
        2 => '5008',
      ),
    ),
  ),
)

또는:

array (
  'earth' => 
  array (
    'germany' => 
    array (
      'cars' => 
      array (
        'bmw' => 
        array (
          0 => 'm4',
          1 => 'x3',
          2 => 'x8',
        ),
      ),
    ),
  ),
  'mars' => 
  array (
    'france' => 
    array (
      'cars' => 
      array (
        'peugeot' => 
        array (
          0 => '206',
          1 => '3008',
          2 => '5008',
        ),
      ),
    ),
  ),
)

아래 메서드를 호출하면이 두 배열 모두 결과를 얻습니다.

array (
  0 => 
  array (
    0 => 'm4',
    1 => 'x3',
    2 => 'x8',
  ),
  1 => 
  array (
    0 => '206',
    1 => '3008',
    2 => '5008',
  ),
)

그래서 나는 동일하게 유지되어야하는 마지막 배열 차원으로 평평하게 만들고 있습니다. 아래 방법은 실제로 어떤 종류의 수준에서 멈출 수 있도록 리팩토링 될 수 있습니다.

function flattenAggregatedArray($aggregatedArray) {
    $final = $lvls = [];
    $counter = 1;
    $lvls[$counter] = $aggregatedArray;


    $elem = current($aggregatedArray);

    while ($elem){
        while(is_array($elem)){
            $counter++;
            $lvls[$counter] = $elem;
            $elem =  current($elem);
        }

        $final[] = $lvls[$counter];
        $elem = next($lvls[--$counter]);
        while ( $elem  == null){
            if (isset($lvls[$counter-1])){
                $elem = next($lvls[--$counter]);
            }
            else{
                return $final;
            }
        }
    }
}

-1

특정 키의 값에만 관심이있는 경우이 접근 방식이 유용 할 수 있습니다.

function valuelist($array, $array_column) {
    $return = array();
    foreach($array AS $row){
        $return[]=$row[$array_column];
    };
    return $return;
};

예:

주어진 $ get_role_action =

array(3) {
  [0]=>
  array(2) {
    ["ACTION_CD"]=>
    string(12) "ADD_DOCUMENT"
    ["ACTION_REASON"]=>
    NULL
  }
  [1]=>
  array(2) {
    ["ACTION_CD"]=>
    string(13) "LINK_DOCUMENT"
    ["ACTION_REASON"]=>
    NULL
  }
  [2]=>
  array(2) {
    ["ACTION_CD"]=>
    string(15) "UNLINK_DOCUMENT"
    ["ACTION_REASON"]=>
    NULL
  }
}

보다 $variables['role_action_list']=valuelist($get_role_action, 'ACTION_CD');초래 :

$variables["role_action_list"]=>
  array(3) {
    [0]=>
    string(12) "ADD_DOCUMENT"
    [1]=>
    string(13) "LINK_DOCUMENT"
    [2]=>
    string(15) "UNLINK_DOCUMENT"
  }

여기에서 다음과 같이 값 조회를 수행 할 수 있습니다.

if( in_array('ADD_DOCUMENT', $variables['role_action_list']) ){
    //do something
};

이것은 같은 이름의 CFML 함수의 PHP 녹 오프입니다.
Jeromy French

나는 잘못된 질문에 대한 정답이기 때문에 반대표를 던졌습니다.
mickmackusa

-1

이 중 어느 것도 나를 위해 작동하지 않았으므로 직접 실행해야했습니다. 잘 작동합니다.

function arrayFlat($arr){
$out = '';
    foreach($arr as $key => $value){

        if(!is_array($value)){
            $out .= $value.',';
        }else{
            $out .= $key.',';
            $out .= arrayFlat($value);
        }

    }
    return trim($out,',');
}


$result = explode(',',arrayFlat($yourArray));
echo '<pre>';
print_r($result);
echo '</pre>';

이 코드 전용 답변은 원하는대로 작동하지 않습니다. 3v4l.org/U3bfp < -proof 이것이 내 반대 투표 의 이유입니다.
mickmackusa

-1

다차원 배열이 주어지고이를 1 차원으로 변환하는 경우 배열이있는 모든 값을 설정 해제하고이를 1 차원으로 저장하면됩니다. 예를 들면 다음과 같습니다.

function _flatten_array($arr) {
  while ($arr) {
    list($key, $value) = each($arr); 
    is_array($value) ? $arr = $value : $out[$key] = $value;
    unset($arr[$key]);
  }
  return (array)$out;
}

이 답변은 어떤 버전에서도 작동하지 않기 때문에 반대 투표를했습니다. 3v4l.org/7cO9N (Proof) 또한 each()php7.2에서 더 이상 사용되지 않습니다.
mickmackusa
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.