Spunkie
Spunkie

Reputation: 147

How to alphabetize array while retaining tree hierarchy?

I have 2 arrays of unknown length/depth that look something like this

[1] => Hand Tools
[2] => Power Tools
[4] =>  ╚═►Outdoor Tools
[6] =>    ╚═►dvjdg
[5] =>  ╚═►Indoor Tools
[7] =>    ╚═►blaha
[8] =>    ╚═►blahb
[3] => Garden Tools

and

[1] => 0
[2] => 0
[4] => 1
[6] => 2
[5] => 1
[7] => 2
[8] => 2
[3] => 0

Both arrays use a category id as the array index and the second array contains the depth of each category. The first array is used to generate a HTML <select> input but I now need to alphabetize this array while maintaining the proper category hierarchy. So I would need to get an output array like this.

[3] => Garden Tools
[1] => Hand Tools
[2] => Power Tools
[5] =>  ╚═►Indoor Tools
[7] =>    ╚═►blaha
[8] =>    ╚═►blahb
[4] =>  ╚═►Outdoor Tools
[6] =>    ╚═►dvjdg

How can I accomplish this?

Upvotes: 3

Views: 224

Answers (1)

hakre
hakre

Reputation: 197680

Considering that $list is your array, you can not easily sort it because each "sub"-element does not carry the information (text) of it's parent. So first thing is to add that information:

  1. Obtain the level.
  2. Set the current value for that level.
  3. Remove higher levels.
  4. Merge together all levels with a character that is not used in texts.

And you've got the sortkey. Do this for all list entries and you've got all sortkeys:

$sortkeys = [];
$levels   = [];
foreach ($list as $index => $entry) {
    $level            = strspn($entry, ' ');
    $levels[$level]   = $entry;
    $sortkey          = implode('|', array_slice($levels, 0, $level + 1));
    $sortkeys[$index] = $sortkey;
}

This example simplifies to obtain the level information. I have counted one space per level. You might have different and use a different function than strspn for that. Most likely you will use your second array for that. I was too lazy to type it, so I did it with the function. Your might just be:

$level = $category_levels[$index];

Now you can sort the $list array based on the $sortkeys array. That can be done with PHPs' array_multisort function. Because that function would re-number numerical keys, we sort the keys as well and then combine after the sorting to preserve them:

$keys = array_keys($list);
array_multisort($sortkeys, SORT_ASC, $list, $keys);

print_r(array_combine($keys, $list));

Which gives you:

Array
(
    [3] => Garden Tools
    [1] => Hand Tools
    [2] => Power Tools
    [5] =>  ╚═►Indoor Tools
    [7] =>   ╚═►blaha
    [8] =>   ╚═►blahb
    [4] =>  ╚═►Outdoor Tools
    [6] =>   ╚═►dvjdg
)

Watch the full example running: Demo

Upvotes: 2

Related Questions