Asked  8 Months ago    Answers:  5   Viewed   33 times

Possible Duplicate:
PHP convert nested array to single array while concatenating keys?
Get array's key recursively and create underscore seperated string

Please, read the whole question before answering.

I have this multidimensional array:

$data = array(
    'user' => array(
        'email'   => 'user@example.com',
        'name'    => 'Super User',
        'address' => array(
            'billing' => 'Street 1',
            'delivery' => 'Street 2'
        )
    ),
    'post' => 'Hello, World!'
);

I want it flatten, transformed into:

$data = array(
    'user.email' => 'user@example.com',
    'user.name'  => 'Super User',
    'user.address.billing'  => 'Street 1',
    'user.address.delivery' => 'Street 2',
    'post'       => 'Hello, World!'
);

Important:

  • The keys are very important to me. I want them concatenated, separated by periods.

  • It should work with any level of nesting.

Thank you!

 Answers

23

Thanks for all the given answers.

I have transformed it in the following, which is an improved version. It eliminates the need of a root prefix, does not need to use references, it is cleaner to read, and it has a better name:

function array_flat($array, $prefix = '')
{
    $result = array();

    foreach ($array as $key => $value)
    {
        $new_key = $prefix . (empty($prefix) ? '' : '.') . $key;

        if (is_array($value))
        {
            $result = array_merge($result, array_flat($value, $new_key));
        }
        else
        {
            $result[$new_key] = $value;
        }
    }

    return $result;
}
Wednesday, March 31, 2021
 
yosemite
answered 8 Months ago
42
function set_val(array &$arr, $path,$val)
{
   $loc = &$arr;
   foreach(explode('.', $path) as $step)
   {
     $loc = &$loc[$step];
   }
   return $loc = $val;
}
Wednesday, March 31, 2021
 
laurent
answered 8 Months ago
57
header('content-type:text/plain');

$arr = array(
    'a' => array(
        'b' => array(
            'c' => 'hello',
        ),
    ),
    'd' => array(
        'e' => array(
            'f' => 'world',
        ),
    ),
);

//prime the stack using our format
$stack = array();
foreach ($arr as $k => &$v) {
    $stack[] = array(
        'keyPath' => array($k),
        'node' => &$v
    );
}

$lookup = array();

while ($stack) {
    $frame = array_pop($stack);
    $lookup[join('/', $frame['keyPath'])] = &$frame['node'];
    if (is_array($frame['node'])) {
        foreach ($frame['node'] as $key => &$node) {
            $keyPath = array_merge($frame['keyPath'], array($key));
            $stack[] = array(
                'keyPath' => $keyPath,
                'node' => &$node
            );
            $lookup[join('/', $keyPath)] = &$node;
        }
    }
}


var_dump($lookup);
// check functionality
$lookup['a'] = 0;
$lookup['d/e/f'] = 1;
var_dump($arr);

Alternatively you could have done stuff like this to get a reference /w array_pop functionality

end($stack);
$k = key($stack);
$v = &$stack[$k];
unset($stack[$k]);

That works because php arrays have elements ordered by key creation time. unset() deletes the key, and thus resets the creation time for that key.

Wednesday, March 31, 2021
 
avon_verma
answered 8 Months ago
39

When you set cell values individually, you have the option of setting the datatype explicitly, but when you use the fromArray() method, you don't have this option.

However, by default, PHP uses a default value binder to identify datatypes from the values passed, and set the cell datatype accordingly. This default behaviour is defined in a class /PHPExcel/Cell/DefaultValueBinder.php.

So you can create your own value binder, as described in the PHPExcel Documentation, that would set every value as a string datatype.

Something like:

class PHPExcel_Cell_MyColumnValueBinder extends PHPExcel_Cell_DefaultValueBinder implements PHPExcel_Cell_IValueBinder
{
    protected $stringColumns = [];

    public function __construct(array $stringColumnList = []) {
        // Accept a list of columns that will always be set as strings
        $this->stringColumns = $stringColumnList;
    }

    public function bindValue(PHPExcel_Cell $cell, $value = null)
    {
        // If the cell is one of our columns to set as a string...
        if (in_array($cell->getColumn(), $this->stringColumns)) {
            // ... then we cast it to a string and explicitly set it as a string
            $cell->setValueExplicit((string) $value, PHPExcel_Cell_DataType::TYPE_STRING);
            return true;
        }
        // Otherwise, use the default behaviour
        return parent::bindValue($cell, $value);
    }
}

// Instantiate our custom binder, with a list of columns, and tell PHPExcel to use it
PHPExcel_Cell::setValueBinder(new PHPExcel_Cell_MyColumnValueBinder(['A', 'B', 'C', 'E', 'F']));

$objPHPExcel = new PHPExcel();
$objPHPExcel->getActiveSheet()->fromArray($dataArray,null,"A2");
Friday, May 28, 2021
 
Wilk
answered 5 Months ago
59

I wonder what could go wrong with RecursiveArrayIterator, because you only needed to collect the key/value pairs from the iterator using the simplest foreach loop:

$a = [
  0 => ['a' => 1, 'b' => 2],
  1 => ['x' => 3, 'y' => 4],
  2 => 5,
  3 => ['m' => 6, ['k' => 7, 'n' => 8]],
];

$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($a));

foreach ($it as $key => $value) {
  $result[$key] = $value;
}

print_r($result);

Output:

Array
(
    [a] => 1
    [b] => 2
    [x] => 3
    [y] => 4
    [2] => 5
    [m] => 6
    [k] => 7
    [n] => 8
)
Saturday, May 29, 2021
 
njai
answered 5 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share