Page 1 of 2
Putting array values as keys in deeper levels
Posted: Thu Jan 11, 2007 11:13 am
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. "level0
a") 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!
Posted: Thu Jan 11, 2007 11:19 am
by feyd
Posted: Thu Jan 11, 2007 7:48 pm
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...
Posted: Thu Jan 11, 2007 8:43 pm
by Kieran Huggins
This sounds like a job for array_merge_recursive()
maybe.
(in place of array_merge)
Wait... what do you want it to do with duplicates?
Posted: Thu Jan 11, 2007 9:26 pm
by feyd
Look further into the thread....
Posted: Fri Jan 12, 2007 5:08 am
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] => #
)
)
)
Posted: Fri Jan 12, 2007 5:19 am
by Kieran Huggins

I'm not sure, but I think that was a compliment.
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.
Posted: Fri Jan 12, 2007 5:33 am
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] => #
)
)
Posted: Fri Jan 12, 2007 5:50 am
by Kieran Huggins
An array is essentially a variable, right? How would you compare two variables normally?
Posted: Fri Jan 12, 2007 7:05 am
by lwc
If this is a joke that I should just use "!=" then remember that $menu contains $string3 and isn't equal to it.
Posted: Fri Jan 12, 2007 7:23 am
by Kieran Huggins
No joke - try it with test arrays. Does $string3==$string7 ? Try it with the === operator as well.
Posted: Fri Jan 12, 2007 7:32 am
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).
Posted: Sun Jan 14, 2007 9:21 am
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
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;
}
Posted: Sun Jan 14, 2007 10:11 am
by Ollie Saunders
lwc, what are you trying to achieve here, why do you need all this?
Posted: Sun Jan 14, 2007 10:34 am
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] => #
)
)
)