1

How can I transform array#1 into the array#2 structure using php ?

The first Array is the results of a database query on a list of Organisms, each organism is classified with it's Order, Family, Genus, Species. Hierarchically Species are the child classifications of various Genus, and Genus classifications are child classifications of various Families etc .

In namespace terms you could read it like so:

item at index[ 0] ---> Hemiptera.Miridae.Kanakamiris
item at index[ 1] ---> Hemiptera.Miridae.Neophloeobia.incisa

There is a kind of parent/child relationship between the keys of array#1 which is as follows:

  • 'Rank_Order' value is the parent of the 'Rank_Family' value
  • 'Rank_Family' value is the parent of the 'Rank_Genus' value
  • 'Rank_Genus' value is the parent of the 'Rank_Species' value

array#1:

Array
(
    [0] => Array
        (
            ['Rank_Order'] => 'Hemiptera'
            ['Rank_Family'] => 'Miridae'
            ['Rank_Genus'] => 'Kanakamiris'
            ['Rank_Species'] => ''
        )   
    [1] => Array
        (
            ['Rank_Order'] => 'Hemiptera'
            ['Rank_Family'] => 'Miridae'
            ['Rank_Genus'] => 'Neophloeobia'
            ['Rank_Species'] => 'incisa'
        )
    [2] => Array
        (
            ['Rank_Order'] => 'Hemiptera'
            ['Rank_Family'] => 'Noridae'
            ['Rank_Genus'] => 'Canelbia'
            ['Rank_Species'] => 'Arissa'
        )
)

The following array is the array structure i need: array#2:

Array(
    [name]     => 'Hemiptera'
    [children] => Array(

        [0] => Array(
            [name]     => 'Miridae'
            [children] => Array(

                [0] => Array(
                    [name]     => 'Kanakamiris'
                    [children] => Array(
                    )
                )
                [1] => Array(
                    [name]     => 'Neophloeobia'
                    [children] => Array(

                        [0] => Array(
                            [name] => 'incisa'
                            [children] => Array(
                            )
                        )
                    )
                )
            )
        )
        [1] => Array(
            [name]     => 'Noridae'
            [children] => Array(

                [0] => Array(
                    [name]     => 'Canelbia'
                    [children] => Array(

                        [0] => Array(
                            [name] => 'Arissa'
                            [children] => Array(
                            )
                        )
                    )
                )
            )
        )
    )
)

I see similar questions asked in stack overflow, though have not been able to use them in my case. eg. php-reorder-array-to-reflect-parent-id-hierarchy

14
  • What's the motivation for the change and why not use OOP ? Commented Aug 16, 2012 at 5:34
  • 2
    You say that similar questions aren't usable in your case, but don't provide us any details about your specific array structure... what is you question?? Commented Aug 16, 2012 at 5:36
  • I want to take the first array and create the second array from it. I will edit the statement between the two code blocks to be a question, apologies Commented Aug 16, 2012 at 5:40
  • The motivation for this is that the second array is the structure i require before i encode the array into JSON and use it for another purpose Commented Aug 16, 2012 at 5:45
  • 1
    it's not clear how does the first array translates into the second since the key-names are different. Also, why not convert it into json directly, why do you have to go through another phase of a nested array ? Commented Aug 16, 2012 at 5:49

1 Answer 1

2

I don't think this will be super-efficient for really large arrays, but it works for your scenario (here's a sample).

 $array = ...
 $levels = array('Rank_Order', 'Rank_Family', 'Rank_Genus', 'Rank_Species');

 function get_children($parent, $lev, $orig, $levels){
     if($lev + 1 > count($levels)){
          return array();
     }

     $seen = array();
     $children = array();
     foreach($orig as $node){
         if($node[$levels[$lev]] == $parent && !in_array($node[$levels[$lev+1]], $seen)){
             $seen[] = $node[$levels[$lev+1]];
             $children[] = get_children($node[$levels[$lev+1]], $lev+1, $orig, $levels);
         }
     }
     return array('name' => $parent, 'children' => $children);
 }

 function hier($orig, $levels){
     $seen = array();
     $result = array();
     foreach($orig as $node){
         if(!in_array($node[$levels[0]], $seen)){
              $seen[] = $node[$levels[0]];
              $result[] = get_children($node[$levels[0]], 0, $orig, $levels);
         }
     }
     return $result;
 }

 print_r($array);
 print_r(hier($array, $levels));
Sign up to request clarification or add additional context in comments.

6 Comments

it seems $result needs to be pushed in somewhere. i'm trying to understand where
@johowie: ah, I missed the initialization in the second function, but it's not actually required. You just need to capture the output of a call to hier
that is indeed working as required, though computation time does seem to be a problem.
@johowie, it's not clear to me that one can do better. This will take at most O(MN) time for depth M and N distinct root elements, and should do much better for complete hierarchies. Here, M is constant, so the algorithm's complexity, believe it or not, is linear.
in hier() it seems the return $seen; should be return $result;, is that correct ?. when I run this php script it takes ages on my local host (MAMP) and with arrays larger than a handful of nodes it simply times out with a server error. Your example @Mark on ideone.com works considerably faster. I cant work out why my localhost doesn't like this !
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.