Reputation: 26624
I currently have coded a way to turn a multidimensional array to comma separated values (I'm using pipes instead of commas for ease of debugging). The problem is, I know that the code I use to do this is bloody awful. It works how I want it to, but it's not nice at all.
What I need
Currently the arr_to_csv()
function works for five levels of nested data within the multidimensional array. I need a recursive function to perform the same for one or an unlimited number of nested arrays, or a good nudge in the right direction. Recursion is not my strong point at all, but I know it's the way forward.
Data input
A multi-dimensional array is passed to the function.
array
'name' =>
array
'singular' => null
'plural' => null
'fields' =>
array
'price' =>
array
'label' => string 'Preis' (length=5)
'company_id' =>
array
'label' => null
'placeholder' => null
//...the array could go on...
The function returns the following...
This is exactly what I want...
0 => string 'name||singular||null' (length=20)
1 => string 'name||plural||null' (length=18)
2 => string 'fields||price||label||Preis' (length=27)
3 => string 'fields||company_id||label||null' (length=31)
4 => string 'fields||company_id||placeholder||null' (length=37)
5 => string 'fields||name||label||null' (length=25)
6 => string 'fields||name||placeholder||null' (length=31)
My horrible constructed function
I'm no good with recursion, so here's my awful list of foreach
s. As you can see from the below code, this is terrible (no need to read the whole thing, it just copies itself). Please help me sort out my horrible code!
function arr_to_csv($data,$csv = '||') {
$array = array();
/* Epic amount of for each's. This could be done with recursion */
foreach($data as $key => &$value) {
if (!is_array($value)) {
$array[] = $key . $csv .(is_null($value)?'null':$value);
} else {
foreach ($value as $k => &$v) {
if (!is_array($v)) {
$array[] = $key . $csv . $k . $csv . (is_null($v) ? 'null' : $v);
} else {
foreach ($v as $kk => &$vv) {
if (!is_array($vv)) {
$array[] = $key . $csv . $k . $csv . $kk . $csv . (is_null($vv) ? 'null' : $vv);
} else {
foreach ($vv as $x => &$y) {
if (!is_array($y)) {
$array[] = $key . $csv . $k . $csv . $kk . $csv. $x . $csv . (is_null($y) ? 'null' : $y);
} else {
foreach ($y as $too => $long) {
if(!is_array($long)) {
$array[] = $key . $csv . $k . $csv . $kk . $csv. $x . $csv . $too . $csv. (is_null($long)?'null':$long);
} else {
foreach ($long as $omg => $why) {
if(!is_array($why)) {
$array[] = $key . $csv . $k . $csv . $kk . $csv. $x . $csv . $too . $csv . $omg . $csv . (is_null($why) ? 'null' : $why);
}
}
}
}
}
}
}
}
}
}
}
}
return $array;
}
Upvotes: 1
Views: 7121
Reputation: 146360
This is some pseudocode, but it is a start:
$strings = [];
$flattenArray = function($arr, $level) use (&$strings, &$flattenArray) {
foreach($arr as $key=>$value){
$s = &$strings[$level];
if(!isset($s)) { $s = array(); }
$s[] = $key;
if(is_array($value)) {
$flattenArray($value, $level);
}
else {
$s[] = $value;
}
$level ++;
}
};
$flattenArray($myArray, 0);
foreach($strings as &$arr) {
$arr = implode("||", $arr);
}
Small demo with your array: http://codepad.viper-7.com/CR2SPY <-- It does not work fully, but it is a start
Here is a demo that I think works the way you want: http://codepad.viper-7.com/shN4pH
Code:
$strings = [];
$flattenArray = function($arr, $level, $k = null) use (&$strings, &$flattenArray) {
foreach($arr as $key=>$value){
if($k === null) {
$s = &$strings[$key];
}
else {
$s = &$strings[$k];
}
if(!isset($s)) {
$s = array();
}
$str = &$s[$level];
if(!isset($str)) {
$str = array();
if($k !== null) { $str[] = $k; }
}
$str[] = $key;
if(is_array($value)) {
$flattenArray($value, $level, ($k === null) ? $key : $k);
}
else {
$str[] = is_null($value) ? "null" : $value;
}
$level ++;
}
};
$flattenArray($myArray, 0);
$all = [];
foreach($strings as $k => $arr){
$new = array();
foreach($arr as $ky => $ar) {
$all[] = implode("||", $ar);
}
}
print_r($all);
Upvotes: 2
Reputation: 1416
Not sure if this will help you, but would it not be easier to flatten the array first and then format in in the way you want? To flatten the array try this:
$array = "YOUR ARRAY";
$FlatArray = array();
foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $k=>$v)
{
$FlatArray[$k] = $v;
}
Been trying all morning to come up with a recursive function for this. This is as close as I got, Maybe you can improve upon this.
$data = array('name' =>array('singular' => NULL,'plural' => NULL,'fields' =>array('price' =>array('label' =>'Preis','company_id' =>array('label' => NULL,'placeholder' => NULL)))));
function arr_to_csv($data,$csv = '||')
{
$list = "";
foreach($data as $key => &$value)
{
$list .= $key . $csv .((!is_array($value))?(is_null($value)?'null':$value): arr_to_csv($value))."<br>";
}
return $list;
}
print_r(arr_to_csv($data));
Returns This:
name||singular||null
plural||null
fields||price||label||Preis
company_id||label||null
placeholder||null
Upvotes: 1
Reputation: 5183
I didn't check it, so in case it doesn't work it should be corrected.
function readarray($from_array, $addr = array()) {
global $output;
foreach ($from_array as $key => $value) {
if (is_Array($value) && count($value) > 0) {
$addr[] = $key;
readarray($value, $addr);
} else {
$output[] = implode('||', $addr) . $value;
}
}
}
$output = array();
foreach ($my_array as $key=>$value){
readarray($value);
}
// improved to get separate arrays of the root of initial array
Upvotes: 1