Özyinelemeyi veya referanslar kullanmadan bir (bi / çoklu) boyutlu bir dizi düzleştirmek için, PHP, mümkün mü?
Anahtarlar I array_map()
ve array_values()
hatlarında düşünüyorum, göz ardı edilebilir yüzden değerleri tek ilgileniyorum.
Sen Standard PHP Library (SPL) özyineleme "gizlemek" için kullanabilirsiniz.
$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, " ";
}
baskılar
1 2 3 4 5 6 7 8 9
Itibariyle PHP 5.3 kısa çözüm yeni kapaklar sözdizimi ile array_walk_recursive()
a> gibi görünüyor:
function flatten(array $array) {
$return = array();
array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
return $return;
}
Burada verimli bir yanıt bulamadı olarak ben, neredeyse 3,5 yıl sonra cevap ilanıyla.
Solution for 2 dimensional array
Bu deneyin:
$array = your array
$result = call_user_func_array('array_merge', $array);
echo "<pre>";
print_r($result);
EDIT: 21-Ağustos-13
Here is the solution which works for multi-dimensional array :
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);
Ref: http://php.net/manual/en/function.call-user-func-array.php
Özyineleme kullanır. Ne kadar karmaşık değil görünce Umarım ne kadar karmaşık değil görünce, özyineleme korku kaybolacaktır.
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>';
Çıktı:
<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>
W / o özyinelemeye (istediğin gibi) düzleştirmek için, bir stack kullanabilirsiniz. Doğal array_flatten
gibi kendi bir fonksiyon içine koyabilirsiniz. Aşağıdaki tuşları w / o çalışan bir versiyonu:.
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;
}
Öğeleri kendi sırayla işlenir. Alt öğeleri yığının üstüne taşınmış olacak çünkü, onlar bir sonraki işlenecektir.
Bir de hesaba anahtarlarını almak mümkün, ancak, yığın işlemek için farklı bir strateji gerekir. Eğer alt dizilerde olası yinelenen tuşları ile uğraşmak gerekir, çünkü bu gerekli oluyor. Ilgili bir soruya da benzer bir cevap: PHP Walk through multidimensional array while preserving keys
Ben özellikle emin değilim, ama II geçmişte bu test vardı: RecurisiveIterator
kullanımı özyinelemeye yapar, bu yüzden gerçekten ihtiyacınız ne bağlıdır. Yanı sıra yığınları dayalı bir özyinelemeli yineleyici oluşturmak mümkün olmalıdır:
foreach(new FlatRecursiveArrayIterator($array) as $key => $value)
{
echo "** ($key) $value\n";
}
I RecursiveIterator
ki ben güzel bir fikir olduğunu düşünüyorum dayalı yığın uygulamak için, şimdiye kadar bunu yapmak değildi.
Hile referans kaynak ve hedef dizileri geçiyor.
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);
Bu sürüm, derin sığ, ya da düzeyleri belirli sayıda yapabilirsiniz:
/**
* @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;
}
Sadece bu bir kat olduğuna işaret düşündüm, bu yüzden array_reduce kullanılabilir:
array_reduce($my_array, 'array_merge', array());
EDIT: Bu seviyelerden herhangi sayıda düzleştirmek için oluşabilir unutmayın. Biz çeşitli şekillerde yapabilirsiniz:
// 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))));
Tabii ki, biz de döngüler kullanabilirsiniz ama soru array_map veya array_values çizgisinde bir combinator işlevi sorar.
/**
* 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));
}
);
Ben HTML girdi biçimi PHP çok boyutlu diziyi temsil etmek gerekiyordu.
$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"
}
Nesnelerin bir dizi var ve sadece kullanmak, bir düğüm ile düzleştirmek istiyorsanız this function:
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;
}