Putting array values as keys in deeper levels

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

lwc
Forum Commoner
Posts: 35
Joined: Thu Jan 11, 2007 11:04 am

Putting array values as keys in deeper levels

Post by lwc »

I think I better demonstrate my problem in code:

Code: Select all

$string = 'level0a=>level1a=>level2a=>level3a';
$array = explode('=>', $string);
print_r($array);


Outputs:
Array
(
    [0] => level0a
    [1] => level1a
    [2] => level2a
    [3] => level3a
)
The problem is I want it to look like:

Code: Select all

Array
Array
(
 [level0a] => Array
             (
              [level1a] => Array
                           (
                           [level2a] => Array
                                        (
                                        [level3a] => Array
                                                     (
                                                     )
                                         )
                           )
             )
)
I stress the "a" (e.g. "level0a") because I have many of these strings and that's why I need each "level" to be an array.

For example:

Code: Select all

$string1 = 'level0a=>level1a=>level2a=>level3a';
$string2 = 'level0b=>level1b=>level2b=>level3b';
$string3 = 'level0c=>level1c';
$string4 = 'level0d=>level1d=>level2d';

And of course they could collide:

Code: Select all

$string5 = 'level0a=>level1e';
$string7 = 'level0a=>level1a=>level2e';
So is there an easy way to do it?

Thanks!
Last edited by lwc on Fri Jan 12, 2007 5:10 am, edited 1 time in total.
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

explode() + viewtopic.php?t=61737 may be of interest. :)
lwc
Forum Commoner
Posts: 35
Joined: Thu Jan 11, 2007 11:04 am

Post by lwc »

The solution offered there ran me into the same problem just as it did there about duplicates - it completely ignores them!

Code: Select all

$string1 = array('level0a', 'level1a', 'level2a', 'level3a');
$string2 = array('level0a', 'level1a', 'level2e');

// $string2 is supposed to add 'level2e' inside the soon to be array 'level1a' inside the soon to be array 'level0a'.

// Now I tried this:
$menu = $levels($string1) + levels($string2); 
echo '<pre>'; print_r($menu); echo '</pre>'; // Turns out the output completely ignores $string2 !

// So I also tried this
$menu = array_merge(levels($string1), levels($string2)); 
echo '<pre>'; print_r($menu); echo '</pre>'; // This time turns out the output completely ignores $string1 !

function levels($row) {
$menu = array();
$t =& $menu;
for($i = 0, $j = count($row)-1; $i < $j; ++$i)
        {
                $t[$row[$i]] = array();
                $t =& $t[$row[$i]];
        }
$t[$row[$i]] = '#';

return $menu;
}
So now I'm lost...
Last edited by lwc on Fri Jan 12, 2007 5:11 am, edited 1 time in total.
User avatar
Kieran Huggins
DevNet Master
Posts: 3635
Joined: Wed Dec 06, 2006 4:14 pm
Location: Toronto, Canada
Contact:

Post by Kieran Huggins »

This sounds like a job for array_merge_recursive() 8)

maybe.

(in place of array_merge)

Wait... what do you want it to do with duplicates?
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

Look further into the thread....
lwc
Forum Commoner
Posts: 35
Joined: Thu Jan 11, 2007 11:04 am

Post by lwc »

feyd, they gave the asker a link for whole project. Learn from Kieran Huggins.
Because Kieran, you rule! Now everything is in there!

Code: Select all

$string1 = array('level0a', 'level1a', 'level2a', 'level3a');
$string2 = array('level0b', 'level1b', 'level2b', 'level3b');
$string3 = array('level0c', 'level1c');
$string4 = array('level0d', 'level1d', 'level2d');
$string5 = array('level0a', 'level1e');
$string6 = array('level0a', 'level1a', 'level2e');

$menu = array();
$menu = array_merge_recursive($menu, levels($string1));
$menu = array_merge_recursive($menu, levels($string2));
$menu = array_merge_recursive($menu, levels($string3));
$menu = array_merge_recursive($menu, levels($string4));
$menu = array_merge_recursive($menu, levels($string5));
$menu = array_merge_recursive($menu, levels($string6));

echo '<pre>';
print_r($menu);
echo '</pre>';

function levels($row) {
$menu = array();
$t =& $menu;
for($i = 0, $j = count($row)-1; $i < $j; ++$i)
        {
                $t[$row[$i]] = array();
                $t =& $t[$row[$i]];
        }
$t[$row[$i]] = '#';

return $menu;
}


Outputs:
Array
(
    [level0a] => Array
        (
            [level1a] => Array
                (
                    [level2a] => Array
                        (
                            [level3a] => #
                        )

                    [level2e] => #
                )

            [level1e] => #
        )

    [level0b] => Array
        (
            [level1b] => Array
                (
                    [level2b] => Array
                        (
                            [level3b] => #
                        )

                )

        )

    [level0c] => Array
        (
            [level1c] => #
        )

    [level0d] => Array
        (
            [level1d] => Array
                (
                    [level2d] => #
                )

        )

)
Last edited by lwc on Fri Jan 12, 2007 5:42 am, edited 1 time in total.
User avatar
Kieran Huggins
DevNet Master
Posts: 3635
Joined: Wed Dec 06, 2006 4:14 pm
Location: Toronto, Canada
Contact:

Post by Kieran Huggins »

8O I'm not sure, but I think that was a compliment. :oops:

I still worship you, feyd!

And that's the other reason I was going to change my username... everyone: JUST CALL ME KIERAN. My signature is too subtle.
lwc
Forum Commoner
Posts: 35
Joined: Thu Jan 11, 2007 11:04 am

Post by lwc »

"You rule" usually is a compliment. :)

Anyway, now I'd like to ask what about complete copies? Is there a way to identify them and skip to the next array?
Not only is it a waste, but it ruins things!

Code: Select all

$string3 = array('level0c', 'level1c');
.
.
.
$string7 = array('level0c', 'level1c');
.
.
.
if (???) // Don't bother doing this if it already matches the current $menu (which already contains $string3)
$menu = array_merge_recursive($menu, levels($string7)); 


Without an if clause, it not only wastes resources but outputs:
Array
(
    [level0c] => Array
        (
            [level1c] => Array
                (
                    [0] => #
                    [1] => #
                )

        )

)

When it should be (with a proper if clause that would skip the already existing array):
Array
(
[level0c] => Array 
        ( 
            [level1c] => # 
        ) 
)
User avatar
Kieran Huggins
DevNet Master
Posts: 3635
Joined: Wed Dec 06, 2006 4:14 pm
Location: Toronto, Canada
Contact:

Post by Kieran Huggins »

An array is essentially a variable, right? How would you compare two variables normally?
lwc
Forum Commoner
Posts: 35
Joined: Thu Jan 11, 2007 11:04 am

Post by lwc »

If this is a joke that I should just use "!=" then remember that $menu contains $string3 and isn't equal to it.
Last edited by lwc on Fri Jan 12, 2007 7:30 am, edited 2 times in total.
User avatar
Kieran Huggins
DevNet Master
Posts: 3635
Joined: Wed Dec 06, 2006 4:14 pm
Location: Toronto, Canada
Contact:

Post by Kieran Huggins »

No joke - try it with test arrays. Does $string3==$string7 ? Try it with the === operator as well.
lwc
Forum Commoner
Posts: 35
Joined: Thu Jan 11, 2007 11:04 am

Post by lwc »

You don't get it. Yes, $string3==$string7, but we're talking about $menu and not $string3.
$menu contains $string3 as well as other things, so $menu != $string3.

I've also tried

Code: Select all

if (!in_array(levels($string7), $menu))
But it thinks it's false even though $string7 is already contained in $menu (because $menu contains $string3, which is identical to $string7).
lwc
Forum Commoner
Posts: 35
Joined: Thu Jan 11, 2007 11:04 am

Post by lwc »

Ok, after I did everything I could think of to get rid of duplicates, I've decided the "#" approach just isn't worth it.
Instead I've decided to use

Code: Select all

$t[$row[$i]] = array();
and just let duplicated arrays being merged, but without any effect. The only downside is that it wastes time merging already existing arrays (but, again, at least now it does no harm).

Anyway, later on when I crawl the menu and want to decide whether I've reached a dead end, I'd just compare the current key to array() instead of to "#".

Code: Select all

$string1 = array('level0a', 'level1a', 'level2a', 'level3a');
$string2 = array('level0c', 'level1c');
$string3 = array('level0c', 'level1c');
$string4 = array('level0d', 'level1d', 'level2d');
$string5 = array('level0a', 'level1a');
$string6 = array('level0a', 'level1a', 'level2e');
$string7 = array('level0c', 'level1c', 'level2z');

$menu = array();
$menu = array_merge_recursive($menu, levels($string1));
$menu = array_merge_recursive($menu, levels($string2));
$menu = array_merge_recursive($menu, levels($string3));
$menu = array_merge_recursive($menu, levels($string4));
$menu = array_merge_recursive($menu, levels($string5));
$menu = array_merge_recursive($menu, levels($string6));
$menu = array_merge_recursive($menu, levels($string7));

echo '<pre>';
print_r($menu);
echo '</pre>';

function levels($row) {
$menu = array();
$t =& $menu;
for($i = 0, $j = count($row)-1; $i < $j; ++$i)
        {
                $t[$row[$i]] = array();
                $t =& $t[$row[$i]];
        }
$t[$row[$i]] = array();

return $menu;
}
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

lwc, what are you trying to achieve here, why do you need all this?
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

A few simple tweaks of the code posted in the thread I linked seems to do what you were wishing..

Code: Select all

<?php

$test = array(
	array('level0a', 'level1a', 'level2a', 'level3a'),
	array('level0c', 'level1c'),
	array('level0c', 'level1c'),
	array('level0d', 'level1d', 'level2d'),
	array('level0a', 'level1a'),
	array('level0a', 'level1a', 'level2e'),
	array('level0c', 'level1c', 'level2z'),
);

$menu = array();
foreach($test as $row)
{
	//unset($row['id']);
	$row = array_values($row);
	$row = array_filter($row);
	$t =& $menu;
	for($i = 0, $j = count($row)-1; $i < $j; ++$i)
	{
		if (!array_key_exists($row[$i], $t) or !is_array($t[$row[$i]]))
		{
			$t[$row[$i]] = array();
		}
		$t =& $t[$row[$i]];
	}
	if (!array_key_exists($row[$i], $t))
	{
		$t[$row[$i]] = '#';
	}
}

print_r($menu);

?>
outputs

Code: Select all

Array
(
    [level0a] => Array
        (
            [level1a] => Array
                (
                    [level2a] => Array
                        (
                            [level3a] => #
                        )

                    [level2e] => #
                )

        )

    [level0c] => Array
        (
            [level1c] => Array
                (
                    [level2z] => #
                )

        )

    [level0d] => Array
        (
            [level1d] => Array
                (
                    [level2d] => #
                )

        )

)
Post Reply