PHP에서 재귀 또는 참조를 사용하지 않고 (bi / multi) 차원 배열을 평평하게 할 수 있습니까?
값에만 관심이 있으므로 키를 무시할 수 있습니다 . array_map()
및 의 줄을 생각 하고 array_values()
있습니다.
PHP에서 재귀 또는 참조를 사용하지 않고 (bi / multi) 차원 배열을 평평하게 할 수 있습니까?
값에만 관심이 있으므로 키를 무시할 수 있습니다 . array_map()
및 의 줄을 생각 하고 array_values()
있습니다.
답변:
당신이 사용할 수있는 표준 PHP 라이브러리 (SPL)을 "숨기기"재귀에.
$a = array(1,2,array(3,4, array(5,6,7), 8), 9);
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($a));
foreach($it as $v) {
echo $v, " ";
}
인쇄물
1 2 3 4 5 6 7 8 9
iterator_to_array($it, false)
foreach의 필요성을 피하십시오.
function flatten($arr){ $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr)); return iterator_to_array($it, true); }
. 다른 사람들에게 도움이되기를 바랍니다.
현재 PHP 5.3 , 최단 솔루션이 될 것으로 보인다 array_walk_recursive()
새로운 클로저 구문 :
function flatten(array $array) {
$return = array();
array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
return $return;
}
use
array_walk_recursive
$userdata
2 차원 배열 솔루션
이것을 시도하십시오 :
$array = your array
$result = call_user_func_array('array_merge', $array);
echo "<pre>";
print_r($result);
편집 : 21-Aug-13
다차원 배열에 작동하는 솔루션은 다음과 같습니다.
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);
참조 : http://php.net/manual/en/function.call-user-func-array.php
call_user_func_array('array_merge', [])
(빈 배열에 주목) null을 반환하고 PHP 경고 오류를 트리거합니다. 배열이 비어 있지 않다는 사실을 알고 있으면 매끄러운 솔루션이지만 많은 사람들이 할 수있는 일반적인 가정은 아닙니다.
$result = $array ?call_user_func_array('array_merge', $array) : [];
PHP 5.6 이상에서는 연산자로 array_merge
외부 배열의 압축을 푼 후 2 차원 배열을 평탄화 할 수 있습니다 ...
. 코드는 간단하고 명확합니다.
array_merge(...$a);
이것은 연관 배열 컬렉션에서도 작동합니다.
$a = [[10, 20], [30, 40]];
$b = [["x" => "X", "y" => "Y"], ["p" => "P", "q" => "Q"]];
print_r(array_merge(...$a));
print_r(array_merge(...$b));
Array
(
[0] => 10
[1] => 20
[2] => 30
[3] => 40
)
Array
(
[x] => X
[y] => Y
[p] => P
[q] => Q
)
그러나 외부 배열에 숫자가 아닌 키가 있으면 작동하지 않습니다. 이 경우 array_values
먼저 전화해야합니다 .
$c = ["a" => ["x" => "X", "y" => "Y"], "b" => ["p" => "P", "q" => "Q"]];
print_r(array_merge(...array_values($c)));
Array
(
[x] => X
[y] => Y
[p] => P
[q] => Q
)
업데이트 : @MohamedGharib의 코멘트에 근거
외부 배열이 비어 있으면 array_merge
인수가 0으로 호출 되므로 오류가 발생합니다 . 빈 배열을 첫 번째 인수로 추가하면 피할 수 있습니다.
array_merge([], ...$a);
array_merge([], ...$a);
요청없이 재귀없이 평평하게하기 위해 stack을 사용할 수 있습니다 . 당연히 이것을 자신의 기능에 넣을 수 있습니다 array_flatten
. 다음은 키없이 작동하는 버전입니다.
function array_flatten(array $array)
{
$flat = array(); // initialize return array
$stack = array_values($array); // initialize stack
while($stack) // process stack until done
{
$value = array_shift($stack);
if (is_array($value)) // a value to further process
{
$stack = array_merge(array_values($value), $stack);
}
else // a value to take
{
$flat[] = $value;
}
}
return $flat;
}
요소는 순서대로 처리됩니다. 하위 요소는 스택 위로 이동하므로 다음에 처리됩니다.
키를 고려하는 것도 가능하지만 스택을 처리하려면 다른 전략이 필요합니다. 하위 배열에서 가능한 중복 키를 처리해야하기 때문에 필요합니다. 관련 질문에 대한 비슷한 대답 : PHP 키를 유지하면서 다차원 배열을 통해 걷기
확실하지는 않지만 II는 과거에 이것을 테스트했습니다 RecurisiveIterator
.The recursion을 사용하므로 실제로 필요한 것에 달려 있습니다. 스택을 기반으로 재귀 반복자를 만들 수 있어야합니다.
foreach(new FlatRecursiveArrayIterator($array) as $key => $value)
{
echo "** ($key) $value\n";
}
나는 그것이 RecursiveIterator
좋은 생각이라고 생각 하는 스택을 구현하기 위해 지금까지하지 않았다 .
if(!empty($value)){$flat[] = $value}
결과 배열에 추가 빈 존재를 방지하기 위해 다른 문 내부. 멋진 기능!
간단 하고 한 줄 답변.
function flatten_array(array $array)
{
return iterator_to_array(
new \RecursiveIteratorIterator(new \RecursiveArrayIterator($array)));
}
용법:
$array = [
'name' => 'Allen Linatoc',
'profile' => [
'age' => 21,
'favourite_games' => [ 'Call of Duty', 'Titanfall', 'Far Cry' ]
]
];
print_r( flatten_array($array) );
출력 (PsySH) :
Array
(
[name] => Allen Linatoc
[age] => 21
[0] => Call of Duty
[1] => Titanfall
[2] => Far Cry
)
이제 키를 처리하는 방법은 이제 당신에게 달려 있습니다. 건배
편집 (2017-03-01)
Nigel Alderton 의 우려 / 문제 인용 :
명확히하기 위해 키 (숫자조차도)를 유지하므로 동일한 키를 가진 값이 손실됩니다. 예를 들어
$array = ['a',['b','c']]
이된다Array ([0] => b, [1] => c )
. 의 키가'a'
있기 때문에'b'
0
인용 Svish 의 답변 :
iterator_to_array 호출에 두 번째 매개 변수
($use_keys)
로 false를 추가 하십시오.
$array = ['a',['b','c']]
이된다 Array ([0] => b, [1] => c )
. 의 키도 'a'
있으므로이 ( 가) 손실되었습니다 . 'b'
0
재귀를 사용합니다. 그것이 복잡하지 않은 것을 보았을 때, 재복에 대한 두려움은 그것이 복잡하지 않은 것을 보았을 때 사라질 것입니다.
function flatten($array) {
if (!is_array($array)) {
// nothing to do if it's not an array
return array($array);
}
$result = array();
foreach ($array as $value) {
// explode the sub-array, and add the parts
$result = array_merge($result, flatten($value));
}
return $result;
}
$arr = array('foo', array('nobody', 'expects', array('another', 'level'), 'the', 'Spanish', 'Inquisition'), 'bar');
echo '<ul>';
foreach (flatten($arr) as $value) {
echo '<li>', $value, '</li>';
}
echo '<ul>';
산출:
<ul><li>foo</li><li>nobody</li><li>expects</li><li>another</li><li>level</li><li>the</li><li>Spanish</li><li>Inquisition</li><li>bar</li><ul>
방금 이것이 폴드이므로 array_reduce를 사용할 수 있다고 생각했습니다.
array_reduce($my_array, 'array_merge', array());
편집 : 이것은 여러 레벨을 평평하게 구성 할 수 있습니다. 여러 가지 방법으로이 작업을 수행 할 수 있습니다.
// Reduces one level
$concat = function($x) { return array_reduce($x, 'array_merge', array()); };
// We can compose $concat with itself $n times, then apply it to $x
// This can overflow the stack for large $n
$compose = function($f, $g) {
return function($x) use ($f, $g) { return $f($g($x)); };
};
$identity = function($x) { return $x; };
$flattenA = function($n) use ($compose, $identity, $concat) {
return function($x) use ($compose, $identity, $concat, $n) {
return ($n === 0)? $x
: call_user_func(array_reduce(array_fill(0, $n, $concat),
$compose,
$identity),
$x);
};
};
// We can iteratively apply $concat to $x, $n times
$uncurriedFlip = function($f) {
return function($a, $b) use ($f) {
return $f($b, $a);
};
};
$iterate = function($f) use ($uncurriedFlip) {
return function($n) use ($uncurriedFlip, $f) {
return function($x) use ($uncurriedFlip, $f, $n) {
return ($n === 0)? $x
: array_reduce(array_fill(0, $n, $f),
$uncurriedFlip('call_user_func'),
$x);
}; };
};
$flattenB = $iterate($concat);
// Example usage:
$apply = function($f, $x) {
return $f($x);
};
$curriedFlip = function($f) {
return function($a) use ($f) {
return function($b) use ($f, $a) {
return $f($b, $a);
}; };
};
var_dump(
array_map(
call_user_func($curriedFlip($apply),
array(array(array('A', 'B', 'C'),
array('D')),
array(array(),
array('E')))),
array($flattenA(2), $flattenB(2))));
물론 루프를 사용할 수도 있지만이 질문은 array_map 또는 array_values 행을 따라 결합기 함수를 요청합니다.
fold
4 레벨로 배열 하거나 fold . fold
3 레벨 fold . fold . fold
을 얻 거나 2 레벨을 얻을 수 있습니다. 이렇게하면 버그가 숨겨지지 않습니다. 예. 5D 배열을 평면화하고 싶지만 4D 배열이 제공되면 오류가 즉시 트리거됩니다.
이 솔루션은 비재 귀적입니다. 요소의 순서는 다소 혼합되어 있습니다.
function flatten($array) {
$return = array();
while(count($array)) {
$value = array_shift($array);
if(is_array($value))
foreach($value as $sub)
$array[] = $sub;
else
$return[] = $value;
}
return $return;
}
shifting
배열에서 벗어난 값을 다시 끝에 추가하는 것은별로 의미가 없습니다. 당신이 array_merge()
대신하고 싶었던 것 같아요 ?
나는 이것이 돌연변이 나 익숙하지 않은 클래스를 사용하지 않는 가장 깨끗한 해결책이라고 생각합니다.
<?php
function flatten($array)
{
return array_reduce($array, function($acc, $item){
return array_merge($acc, is_array($item) ? flatten($item) : [$item]);
}, []);
}
// usage
$array = [1, 2, [3, 4], [5, [6, 7]], 8, 9, 10];
print_r(flatten($array));
다음과 같은 간단한 기능을 시도하십시오.
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;
}
그래서 이것으로부터 :
array (
'und' =>
array (
'profiles' =>
array (
0 =>
array (
'commerce_customer_address' =>
array (
'und' =>
array (
0 =>
array (
'first_name' => 'First name',
'last_name' => 'Last name',
'thoroughfare' => 'Address 1',
'premise' => 'Address 2',
'locality' => 'Town/City',
'administrative_area' => 'County',
'postal_code' => 'Postcode',
),
),
),
),
),
),
)
당신은 얻는다 :
array (
'first_name' => 'First name',
'last_name' => 'Last name',
'thoroughfare' => 'Address 1',
'premise' => 'Address 2',
'locality' => 'Town/City',
'administrative_area' => 'County',
'postal_code' => 'Postcode',
)
트릭은 소스 및 대상 배열을 모두 참조로 전달하는 것입니다.
function flatten_array(&$arr, &$dst) {
if(!isset($dst) || !is_array($dst)) {
$dst = array();
}
if(!is_array($arr)) {
$dst[] = $arr;
} else {
foreach($arr as &$subject) {
flatten_array($subject, $dst);
}
}
}
$recursive = array('1', array('2','3',array('4',array('5','6')),'7',array(array(array('8'),'9'),'10')));
echo "Recursive: \r\n";
print_r($recursive);
$flat = null;
flatten_array($recursive, $flat);
echo "Flat: \r\n";
print_r($flat);
// If you change line 3 to $dst[] = &$arr; , you won't waste memory,
// since all you're doing is copying references, and imploding the array
// into a string will be both memory efficient and fast:)
echo "String:\r\n";
echo implode(',',$flat);
/**
* For merging values of a multidimensional array into one
*
* $array = [
* 0 => [
* 0 => 'a1',
* 1 => 'b1',
* 2 => 'c1',
* 3 => 'd1'
* ],
* 1 => [
* 0 => 'a2',
* 1 => 'b2',
* 2 => 'c2',
* ]
* ];
*
* becomes :
*
* $array = [
* 0 => 'a1',
* 1 => 'b1',
* 2 => 'c1',
* 3 => 'd1',
* 4 => 'a2',
* 5 => 'b2',
* 6 => 'c2',
*
* ]
*/
array_reduce
(
$multiArray
, function ($lastItem, $currentItem) {
$lastItem = $lastItem ?: array();
return array_merge($lastItem, array_values($currentItem));
}
);
재귀를 정말로 좋아하지 않는다면 ... 대신 이동하십시오 :)
$a = array(1,2,array(3,4, array(5,6,7), 8), 9);
$o = [];
for ($i=0; $i<count($a); $i++) {
if (is_array($a[$i])) {
array_splice($a, $i+1, 0, $a[$i]);
} else {
$o[] = $a[$i];
}
}
참고 : 이 간단한 버전에서는 배열 키를 지원하지 않습니다.
continue
로 바꾸면 다소 빠릅니다.
재귀 생성기를 사용하는 것은 어떻습니까? https://ideone.com/d0TXCg
<?php
$array = [
'name' => 'Allen Linatoc',
'profile' => [
'age' => 21,
'favourite_games' => [ 'Call of Duty', 'Titanfall', 'Far Cry' ]
]
];
foreach (iterate($array) as $item) {
var_dump($item);
};
function iterate($array)
{
foreach ($array as $item) {
if (is_array($item)) {
yield from iterate($item);
} else {
yield $item;
}
}
}
PHP 5.2의 경우
function flatten(array $array) {
$result = array();
if (is_array($array)) {
foreach ($array as $k => $v) {
if (is_array($v)) {
$result = array_merge($result, flatten($v));
} else {
$result[] = $v;
}
}
}
return $result;
}
이 버전은 깊거나 얕거나 특정 수준의 레벨을 수행 할 수 있습니다.
/**
* @param array|object $array array of mixed values to flatten
* @param int|boolean $level 0:deep, 1:shallow, 2:2 levels, 3...
* @return array
*/
function flatten($array, $level = 0) {
$level = (int) $level;
$result = array();
foreach ($array as $i => $v) {
if (0 <= $level && is_array($v)) {
$v = flatten($v, $level > 1 ? $level - 1 : 0 - $level);
$result = array_merge($result, $v);
} elseif (is_int($i)) {
$result[] = $v;
} else {
$result[$i] = $v;
}
}
return $result;
}
여기 코드 가 무섭게 보이기 때문입니다. 다음은 다차원 배열을 html 형식 호환 구문으로 변환하지만 읽기 쉬운 함수입니다.
/**
* Flattens a multi demensional array into a one dimensional
* to be compatible with hidden html fields.
*
* @param array $array
* Array in the form:
* array(
* 'a' => array(
* 'b' => '1'
* )
* )
*
* @return array
* Array in the form:
* array(
* 'a[b]' => 1,
* )
*/
function flatten_array($array) {
// Continue until $array is a one-dimensional array.
$continue = TRUE;
while ($continue) {
$continue = FALSE;
// Walk through top and second level of $array and move
// all values in the second level up one level.
foreach ($array as $key => $value) {
if (is_array($value)) {
// Second level found, therefore continue.
$continue = TRUE;
// Move each value a level up.
foreach ($value as $child_key => $child_value) {
$array[$key . '[' . $child_key . ']'] = $child_value;
}
// Remove second level array from top level.
unset($array[$key]);
}
}
}
return $array;
}
이것은을 사용하여 달성 할 수 있습니다 array_walk_recursive
$a = array(1,2,array(3,4, array(5,6,7), 8), 9);
array_walk_recursive($a, function($v) use (&$r){$r[]=$v;});
print_r($r);
작업 예 :-https: //3v4l.org/FpIrG
이것은 참조를 사용하여 내 솔루션입니다.
function arrayFlatten($array_in, &$array_out){
if(is_array($array_in)){
foreach ($array_in as $element){
arrayFlatten($element, $array_out);
}
}
else{
$array_out[] = $array_in;
}
}
$arr1 = array('1', '2', array(array(array('3'), '4', '5')), array(array('6')));
arrayFlatten($arr1, $arr2);
echo "<pre>";
print_r($arr2);
echo "</pre>";
<?php
//recursive solution
//test array
$nested_array = [[1,2,[3]],4,[5],[[[6,[7=>[7,8,9,10]]]]]];
/*-----------------------------------------
function call and return result to an array
------------------------------------------*/
$index_count = 1;
$flatered_array = array();
$flatered_array = flat_array($nested_array, $index_count);
/*-----------------------------------------
Print Result
-----------------------------------------*/
echo "<pre>";
print_r($flatered_array);
/*-----------------------------------------
function to flaten an array
-----------------------------------------*/
function flat_array($nested_array, & $index_count, & $flatered_array) {
foreach($nested_array AS $key=>$val) {
if(is_array($val)) {
flat_array($val, $index_count, $flatered_array);
}
else {
$flatered_array[$index_count] = $val;
++$index_count;
}
}
return $flatered_array;
}
?>
이것에 대한 정말 깨끗한 해결책을 찾는 사람은 누구나 있습니다. 옵션은 다음과 같습니다.
$test_array = array(
array('test' => 0, 0, 0, 0),
array(0, 0, 'merp' => array('herp' => 'derp'), 0),
array(0, 0, 0, 0),
array(0, 0, 0, 0)
);
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($test_array));
var_dump( iterator_to_array($it, false) ) ;
인쇄물
0 0 0 0 0 0 derp 0 0 0 0 0 0 0 0 0
솔루션 인 키도 유지하려는 경우.
function reduce(array $array) {
$return = array();
array_walk_recursive($array, function($value, $key) use (&$return) { $return[$key] = $value; });
return $return;
}
불행히도 중간 키없이 최종 중첩 배열 만 출력합니다. 다음 예제의 경우 :
$array = array(
'sweet' => array(
'a' => 'apple',
'b' => 'banana'),
'sour' => 'lemon');
print_r(flatten($fruits));
출력은 다음과 같습니다
Array
(
[a] => apple
[b] => banana
[sour] => lemon
)
HTML 입력 형식으로 PHP 다차원 배열을 표현해야했습니다.
$test = [
'a' => [
'b' => [
'c' => ['a', 'b']
]
],
'b' => 'c',
'c' => [
'd' => 'e'
]
];
$flatten = function ($input, $parent = []) use (&$flatten) {
$return = [];
foreach ($input as $k => $v) {
if (is_array($v)) {
$return = array_merge($return, $flatten($v, array_merge($parent, [$k])));
} else {
if ($parent) {
$key = implode('][', $parent) . '][' . $k . ']';
if (substr_count($key, ']') != substr_count($key, '[')) {
$key = preg_replace('/\]/', '', $key, 1);
}
} else {
$key = $k;
}
$return[$key] = $v;
}
}
return $return;
};
die(var_dump( $flatten($test) ));
array(4) {
["a[b][c][0]"]=>
string(1) "a"
["a[b][c][1]"]=>
string(1) "b"
["b"]=>
string(1) "c"
["c[d]"]=>
string(1) "e"
}
$var['a']['b']['c'][0] = 'a'; ...
입니다.
객체 배열이 있고 노드로 평면화하려는 경우이 함수를 사용하십시오.
function objectArray_flatten($array,$childField) {
$result = array();
foreach ($array as $node)
{
$result[] = $node;
if(isset($node->$childField))
{
$result = array_merge(
$result,
objectArray_flatten($node->$childField,$childField)
);
unset($node->$childField);
}
}
return $result;
}