Jump to content

Walking through and concatenating elements to keys in a large multidimensional


Recommended Posts

I have a large multidimensional array that can exist of any number of Children arrays, each having the potential to have any number of their own children (though, realistically not to exceed a few layers deep before actual values being to appear)

 

For example, my array might look something like this...

Array
(
    [Ford] => Array
    (
        [Mustang] => Array
        (
           [seats] => Array
            (
                [0] => Leather
                [1] => Cloth
            )
            [Trim] => Array
            (
                [0] => Plastic
                [1] => Wood
            )
         )
         [F-150] => Array
         ...
    )
    [Honda] => Array
    ...
)

What I'm trying to do is traverse the array to the lowest child and work backwards.  For example, I'm trying to create a single string (or series of strings) similar to the following

Ford/Mustang/Seats/Leather
Ford/Mustang/Seats/Cloth
Ford/Mustang/Trim/Wood
Ford/Mustang/Trim/Plastic
Ford/F-150/..
....

 

What would be the easiest way to go about this?  Making a function, testing if the child is an array and recalling the function from within the function, until it hits a key value that isn't an array, then walking backwards?  That seems the most logical to me, but then I run into the issue of trying to combine Key names to Key values.

 

Thoughts and/or suggestions?

What would be the easiest way to go about this?  Making a function, testing if the child is an array and recalling the function from within the function, until it hits a key value that isn't an array, then walking backwards?

Yep,

 

Ideally, you'd use a foreach loop. and a string variable ... as well as a recursive function

UNTESTED

$multdimarray = array();
$stringVar = null;
function createString($arr, &$str) {
foreach($arr $k => $v) {
	 if(is_array($v)) {
		  $str .= $k . "/";
		  createString($v, $str);
	 } else {
		  $str .= $v;
	 }
}
}
// Then call it
$mystring($multidimarray, $stringVar);
//    $stringVar will have your stuff.

Alright, I figured that'd be easiest.  One question about your suggestion though - what does this represent?

foreach($arr $k => $v)

$arr is the multidim array, but I've never used foreach() like this before.  Can you give me a brief synopsis of what's you're doing here?

 

Never mind, I RTFM'd :P

Fundamentally, I have the parser working. However what isn't working is how it creates the string in the end.  It, for each array, creates a string that is a concatenation of the entire Toplevel parent array. 

 

Suggestions to circumvent this?  There several elements in the lowest level children arrays.  For each one of those elements, the string portion before the element values needs to remain static.  Once the child array has been exhausted of all values, the process repeats, starting one level higher.

This is what I'm going after...
Ford/Mustang/Seats/Leather
Ford/Mustang/Seats/Cloth
Ford/Mustang/Trim/Wood
Ford/Mustang/Trim/Plastic
Ford/F-150/..

This is what I get...
Ford/Mustang/Seats/Leather
Ford/Mustang/Seats/LeatherCloth
Ford/Mustang/Seats/LeatherClothWood
...

 

Setting the string value to null at the end of the loop doesn't work, as then it loses its current path information, and winds up just dumping the element value of the child array it's walking.

 

Thoughts?  :confused:

 

PS: Thanks Zane for the usage of the amprisand - I had no idea that it had that functionality!

I'll have to ponder of that for a second.

 

You need a counting variable to show that you've reached the end of an array, I'm just not entirely sure where it should go at the moment. :?:

I was thinking that maybe the best way to do it would be to keep track of where the script is in the array, using an index array of numeric values that essentially is just a list.

eg:

$counter = array(1,2,3,4);

And on the fly, just reconstruct the string based on Key/Value names when requested by the string output.  This clearly is a very inefficient way to do it, but it's about the best idea I've got, given my knowledge... :-\

The first issue I foresee though is keeping the array alive/making it available to the child of the function when it spawns itself on each child array...

Here's my take. I use array_merge and a recursive function

 

<?php

$array = array(
'mustang' => array(
	'seats' => array('leather','cloth'),
	'trim' => array('plastic','wood')
),
'f150' => array(
	'seats' => array('leather','cloth'),
	'trim' => array('plastic','wood'),
	'deeper' => array(
		'foo' => array('deep','stuff'),
		'bar' => array('goes','here')
	)
),
'fiesta' => array(
	'engine' => 'tiny'
),
'pinto' => 'don\'t drive'
);

var_dump( flatten($array) );

function flatten( $array, $divide = '/', $str = FALSE) {
$return = array();
foreach( $array as $k => $v ) {
	if( is_array($v) )
		$return = array_merge($return,flatten($v,$divide,$str.$k.$divide));
	else
		$return[] = $str.$v;
}
return $return;
}

?>

 

result

 

array
  0 => string 'mustang/seats/leather' (length=21)
  1 => string 'mustang/seats/cloth' (length=19)
  2 => string 'mustang/trim/plastic' (length=20)
  3 => string 'mustang/trim/wood' (length=17)
  4 => string 'f150/seats/leather' (length=18)
  5 => string 'f150/seats/cloth' (length=16)
  6 => string 'f150/trim/plastic' (length=17)
  7 => string 'f150/trim/wood' (length=14)
  8 => string 'f150/deeper/foo/deep' (length=20)
  9 => string 'f150/deeper/foo/stuff' (length=21)
  10 => string 'f150/deeper/bar/goes' (length=20)
  11 => string 'f150/deeper/bar/here' (length=20)
  12 => string 'fiesta/tiny' (length=11)
  13 => string 'don't drive' (length=11)

 

As you can see, it kinda screws up on single-depth named keys. It's possible to fix this, by checking if the key's numeric, or having a flag off for the initial call, and on during recursion. Figured it wasn't a big deal though.

 

Leave $str as FALSE when calling, unless you want some prefix value in front of each result.

here's mine

 

<?php
$spec = Array
(
    'Ford' => Array
    (
        'Mustang' => Array
        (
           'Seats' => Array
            (
                '0' => 'Leather',
                '1' => 'Cloth'
            ),
            'Trim' => Array
            (
                '0' => 'Plastic',
                '1' => 'Wood'
            )
         ),
        'Focus' => Array
        (
           'Seats' => Array
            (
                '1' => 'Cloth'
            ),
            'Trim' => Array
            (
                '0' => 'Plastic',
            )
         )

    ),
    'BMW' => Array  (
        '5 series' => Array
        (
            'saloon' => array (
               'Seats' => Array
                (
                    '0' => 'Leather',
                    '1' => 'Cloth'
                ),
                'Trim' => Array
                (
                    '0' => 'Plastic',
                    '1' => 'Walnut'
                )
            ),
            'coupe' => array (
               'Seats' => Array
                (
                    '0' => 'Leather',
                    '1' => 'Cloth'
                ),
                'Trim' => Array
                (
                    '0' => 'Plastic',
                    '1' => 'Walnut'
                )
            )
        )
    )
);

$results = array();
getSpec($spec, '', $results);
echo '<pre>'.print_r($results, 1).'</pre>';

function getSpec($arr, $str, &$results)
{
    foreach ($arr as $k => $v) {
        if (is_array($v)) {
            getSpec($v, $str.$k.'/', $results);
        }
        else {
            $results[] = $str.$v;
        }
    }
}
?>

RESULTS-->

Array
(
    [0] => Ford/Mustang/Seats/Leather
    [1] => Ford/Mustang/Seats/Cloth
    [2] => Ford/Mustang/Trim/Plastic
    [3] => Ford/Mustang/Trim/Wood
    [4] => Ford/Focus/Seats/Cloth
    [5] => Ford/Focus/Trim/Plastic
    [6] => BMW/5 series/saloon/Seats/Leather
    [7] => BMW/5 series/saloon/Seats/Cloth
    [8] => BMW/5 series/saloon/Trim/Plastic
    [9] => BMW/5 series/saloon/Trim/Walnut
    [10] => BMW/5 series/coupe/Seats/Leather
    [11] => BMW/5 series/coupe/Seats/Cloth
    [12] => BMW/5 series/coupe/Trim/Plastic
    [13] => BMW/5 series/coupe/Trim/Walnut
)

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.