1

All,

I have the following array and function, which will create a multidimensional array based on array key's that you specific. For every attribute you pass to the function, it will add another dimension to the array. Think of it as array sorting.

The function supplied works great, but it uses eval, I had a hard time coming up with a function which was consistent and threw no errors without it.

Let's start with an array:

$array = array(
          array(‘name’ => ‘Person1’, ‘username’ => ‘username1’, ‘join_date’ => 12233445566, ‘state’ => ‘NJ’),
          array(‘name’ => ‘Person2’, ‘username’ => ‘username2’, ‘join_date’ => 12233445566, ‘state’ => ‘NJ’),
          array(‘name’ => ‘Person3’, ‘username’ => ‘username3’, ‘join_date’ => 12233445996, ‘state’ => ‘NY’),
          array(‘name’ => ‘Person4’, ‘username’ => ‘username4’, ‘join_date’ => 12233445996, ‘state’ => ‘NJ’),
          array(‘name’ => ‘Person5’, ‘username’ => ‘username5’, ‘join_date’ => 12233445566, ‘state’ => ‘NJ’),
          array(‘name’ => ‘Person6’, ‘username’ => ‘username6’, ‘join_date’ => 12233445566, ‘state’ => ‘NY’),
          array(‘name’ => ‘Person7’, ‘username’ => ‘username7’, ‘join_date’ => 12233445776, ‘state’ => ‘NY’),
          array(‘name’ => ‘Person8’, ‘username’ => ‘username8’, ‘join_date’ => 12233445566, ‘state’ => ‘NY’),
          array(‘name’ => ‘Person9’, ‘username’ => ‘username9’, ‘join_date’ => 12233445996, ‘state’ => ‘NJ’),
);

Here is an example function:

function createIndex($array, $index){
   $index_array = array();

   foreach($array as $result){

          if(is_array($index)){
                 $key = '$index_array';
                 for($i=0;$i<=sizeof($index)-1;$i++){
                       $key .= "['{$result[$index[$i]]}']";
                 }
                 $key .= "[]"; 
                 eval("$key = \$result;");
          }
          else{
                 $index_array[$result[$index]] = $result; 
          }
   }

   return $index_array;
}

The Calling function:

print_r(create_index($array, array(‘state’, ‘join_date’)));

The desired output:

Array
(
[NJ] => Array
    (
        [12233445566] => Array
            (
                [0] => Array
                    (
                        [name] => Person1
                        [username] => username1
                        [join_date] => 12233445566
                        [state] => NJ
                    )

                [1] => Array
                    (
                        [name] => Person2
                        [username] => username2
                        [join_date] => 12233445566
                        [state] => NJ
                    )

                [2] => Array
                    (
                        [name] => Person5
                        [username] => username5
                        [join_date] => 12233445566
                        [state] => NJ
                    )

            )

        [12233445996] => Array
            (
                [0] => Array
                    (
                        [name] => Person4
                        [username] => username4
                        [join_date] => 12233445996
                        [state] => NJ
                    )

                [1] => Array
                    (
                        [name] => Person9
                        [username] => username9
                        [join_date] => 12233445996
                        [state] => NJ
                    )

            )

    )

[NY] => Array
    (
        [12233445996] => Array
            (
                [0] => Array
                    (
                        [name] => Person3
                        [username] => username3
                        [join_date] => 12233445996
                        [state] => NY
                    )

            )

        [12233445566] => Array
            (
                [0] => Array
                    (
                        [name] => Person6
                        [username] => username6
                        [join_date] => 12233445566
                        [state] => NY
                    )

                [1] => Array
                    (
                        [name] => Person8
                        [username] => username8
                        [join_date] => 12233445566
                        [state] => NY
                    )

            )

        [12233445776] => Array
            (
                [0] => Array
                    (
                        [name] => Person7
                        [username] => username7
                        [join_date] => 12233445776
                        [state] => NY
                    )

            )

    )

)

The question: What are ways that you would conquer the above to obtain the same results form the same array? I am curious to see how others would do it.

Thanks

1
  • You might consider using a richer data structure. The main problem is that you don't have a solid way to differentiate between a list(numeric, sequential indexes starting at 0) and keys that represent a column that you formed groups over. You could figure this out by looking at the depth....but I think its getting ugly. I guess a simple fix would be to prefix all keys with a string, except the true numeric ones. Commented Jun 6, 2012 at 18:55

3 Answers 3

1

I came up with basically the same solution as posted by Ryan, but I ran into issues when the key was an int ... hence the typecasting to string for the array key ...

function createIndex($set, $indexes)
{
    $return = array();

    if(!is_array($indexes)){
        $indexes = array($indexes);
    }

    foreach($set as $data){
        $curr =& $return;
        foreach($indexes as $index){
            $key  = (string)$data[$index];
            if(!is_array($curr[$key])){
                $curr[$key] = array();
            }
            $curr =& $curr[$key];
        }
        $curr[] = $data;
    }

    return $return;
}
Sign up to request clarification or add additional context in comments.

Comments

1

Here's what I'd do. Also notice how you can pass in $index_array by reference. I personally use this in my code, so I can process large amounts of data in batches and unset data occasionally.

It's all about storing variables by reference:

function create_index($array, $indexes, &$index_array = array()) {
    if(!is_array($indexes)) $indexes = array($indexes);

    foreach($array as $result) {
        $object = &$index_array;

        foreach($indexes as $index){
            if(!array_key_exists((string)$result[$index], $object)) {
                $object[(string)$result[$index]] = array();
            }
            $object = &$object[(string)$result[$index]];
        }
        $object[] = $result;
    }

    return $index_array;
}

Then to use it:

// You can use it like you did in your question:
print_r(create_index($array, array('state', 'join_date')));

// Or you can process in chunks:

$results = array();

while(/* store data from database in $array */) {
    create_index($array, array('state', 'join_date'), &$results);
}

Comments

0

Using references, I was able to come up with the below function. It works great!

It will automatically detect if multiple leafs exist at the end of the tree, and if so, branch, or leaf itself. Also, you can merge, using the $merge_classifier argument. This will allow you to merge columns called count for example, which will add the values together.

function createIndex($keys, Array $array, $merge_classifier = NULL, $return_array = array())
{               

    if(is_string($keys)){
        $tmp = $keys;
        $keys = array();
        $keys[] = $tmp; 
    }

    foreach($array as $result) {
        $object = &$return_array;

        foreach($keys as $index){
            if(!array_key_exists($result[$index], $object)) {
                $object[$result[$index]] = array();
            }
            $object = &$object[$result[$index]];
        }

        if(!is_null($merge_classifier)){
            $object = array_merge($result, array($merge_classifier => ($result[$merge_classifier] + $object[$merge_classifier])));
        }
        else{
            if(sizeof($object) > 0){
                $object[] = $result;    
            }else{
                $object = $result;  
            }
        }
    }

    return $return_array;
}

Comments

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.