Bir çok boyutlu Array düzleştirme nasıl?

14 Cevap php

Ö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.

14 Cevap

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

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";
}

Demo

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);

Php 5.2 için

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;
}

Bu çözüm olmayan özyinelemelidir. Elemanların düzeni biraz karıştırılacaklardır unutmayın.

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;
}

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));
    }
);

Gist snippet

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;
}

Non-recursive basit array_flatten.

function array_flatten($arr) {
    $arr = array_values($arr);
    while (list($k,$v)=each($arr)) {
        if (is_array($v)) {
            array_splice($arr,$k,1,$v);
            next($arr);
        }
    }
    return $arr;
}