4

I have php array structure like this:

array(
    'servicemanagement.scheduler.events.edit' => 'Edit',
    'servicemanagement.scheduler.events.delete' => 'Delete',
    'servicemanagement.scheduler.events' => 'Events',
    'servicemanagement.scheduler' => 'Scheduler',
    'servicemanagement.subscribers' => 'Subscribers',
    'servicemanagement.subscribers.index' => 'Index',
    'servicemanagement' => 'Service management',
);

And I would like to convert is to multidimensional array like:

array(
    'servicemanagement' => array(
        'id' => 'servicemanagement',
        'title' => 'Service Management',
        'children' => array(
            'scheduler' => array(
                'id' => 'servicemanagement.scheduler',
                'title' => 'Scheduler',
                'children' => array(
                    'events' => array(
                        'id' => 'servicemanagement.scheduler.events',
                        'title' => 'Events',
                        'children' => array(
                            'edit' => array(
                                'id' => 'servicemanagement.scheduler.events.edit',
                                'title' => 'Edit',
                                'children' => array(),
                            ),
                            'delete' => array(
                                'id' => 'servicemanagement.scheduler.events.delete',
                                'title' => 'Delete',
                                'children' => array(),
                            ),
                        ),
                    ),
                ),
            ),
            'subscribers' => array(
                'id' => 'servicemanagement.subscribers',
                'title' => 'Subscribers',
                'children' => array(
                    'index' => array(
                        'id' => 'servicemanagement.subscribers.index',
                        'title' => 'Index',
                    )
                ),
            ),
        ),
    ),
);

I have checked some answers already like this one: How to set a deep array in PHP

But it seems that i could not manage to clear up the writing on top of the arrays and the last record 'servicemanagement' removes all of the previous records.

The function that is used there is

function setArray(&$array, $keys, $value) {
    $keys = explode(".", $keys);
    $current = &$array;
    foreach($keys as $key) {
        $current = &$current[$key];
    }
    $current = $value;
}

Another function that I have found but it is not doing the expected result is:

function unflatten($array,$prefix = '')
{
    $result = array();
    foreach($array as $key=>$value)    {
        if (!empty($prefix)) {
            $key = preg_replace('#^'.preg_quote($prefix).'#','',$key);
        }
        if (strpos($key,'.') !== false) {
            parse_str('result['.str_replace('.','][',$key)."]=".$value);
        } else {
            $result[$key] = $value;
        }
    }
    return $result;
}

It is an option to use recursion to unflatten this array since the end format is the same for all records.

May anyone give me a tip ot this one?

6
  • 2
    Hm, I think you have to create a recursive function for that. Commented Jun 28, 2013 at 12:49
  • I once answered similar question, take a look at this Commented Jun 28, 2013 at 12:56
  • @Voitcus it is similar solution to the first example in the post. Commented Jun 28, 2013 at 13:01
  • I don't know exactly what the problem is. Commented Jun 28, 2013 at 13:03
  • When the function processes the last row servicemanagement it overwrites the whole tree and the result is array('servicemanagement' => 'Service Management'); Commented Jun 28, 2013 at 13:05

2 Answers 2

5

I created an unflatten function for reference here:

https://gist.github.com/Gerst20051/b14c05b72c73b49bc2d306e7c8b86223

$results = [
  'id' => 'abc123',
  'address.id' => 'def456',
  'address.coordinates.lat' => '12.345',
  'address.coordinates.lng' => '67.89',
  'address.coordinates.geo.accurate' => true,
];

function unflatten($data) {
  $output = [];
  foreach ($data as $key => $value) {
    $parts = explode('.', $key);
    $nested = &$output;
    while (count($parts) > 1) {
      $nested = &$nested[array_shift($parts)];
      if (!is_array($nested)) $nested = [];
    }
    $nested[array_shift($parts)] = $value;
  }
  return $output;
}

echo json_encode(unflatten($results));

/*
{
  "id": "abc123",
  "address": {
    "id": "def456",
    "coordinates": {
      "lat": "12.345",
      "lng": "67.89",
      "geo": {
        "accurate": true
      }
    }
  }
}
*/

This was slightly influenced by the following resources:

Sign up to request clarification or add additional context in comments.

Comments

2

This isn't the cleanest solution but it works as a single function

    $your_array = array(
        'servicemanagement.scheduler.events.edit' => 'Edit',
        'servicemanagement.scheduler.events.delete' => 'Delete',
        'servicemanagement.scheduler.events' => 'Events',
        'servicemanagement.scheduler' => 'Scheduler',
        'servicemanagement.subscribers' => 'Subscribers',
        'servicemanagement.subscribers.index' => 'Index',
        'servicemanagement' => 'Service management',
    );

    function expand($array, $level = 0)
    {
        $result = array();
        $next = $level + 1;

        foreach($array as $key=>$value) {
            $tree = explode('.', $key);
            if(isset($tree[$level])) {
                if(!isset($tree[$next])) {
                    $result[$tree[$level]]['id'] =  $key;
                    $result[$tree[$level]]['title'] = $value;
                    if(!isset($result[$tree[$level]]['children'])) {
                        $result[$tree[$level]]['children'] = array();
                    }
                } else {
                    if(isset($result[$tree[$level]]['children'])) {
                        $result[$tree[$level]]['children'] = array_merge_recursive($result[$tree[$level]]['children'], expand(array($key => $value), $next));
                    } else {
                        $result[$tree[$level]]['children'] = expand(array($key => $value), $next);
                    }
                }

            }
        }

        return $result;

    }
   var_export(expand($your_array));

2 Comments

It is good enough and it does the job. We can replace $result[$tree[$level]]['id'] = implode('.',array_slice($tree, 0, $next)); with $result[$tree[$level]]['id'] = $key;
I just changed the answer to suit this as it removes unnecessary logic.

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.