2

I want to dissect an array like this:

[
    "ID",
    "UUID",
    "pushNotifications.sent",
    "campaigns.boundDate",
    "campaigns.endDate",
    "campaigns.pushMessages.sentDate",
    "pushNotifications.tapped"
]

To a format like this:

{
    "ID" : 1,
    "UUID" : 1,
    "pushNotifications" : 
        {
            "sent" : 1,
            "tapped" : 1
        },
    "campaigns" :
        {
            "boundDate" : 1,
            "endDate" : 1,
            "pushMessages" :
                {
                    "endDate" : 1
                }  
        }
}

It would be great if I could just set a value on an associative array in a keypath-like manner:

//To achieve this:
$dissected['campaigns']['pushMessages']['sentDate'] = 1;

//By something like this:
$keypath = 'campaigns.pushMessages.sentDate';
$dissected{$keypath} = 1;

How to do this in PHP?

3
  • is that top piece of code suppose to be a string? Commented May 5, 2013 at 21:13
  • Yap. An array of strings (actually array of keypaths). Commented May 5, 2013 at 21:17
  • To have a function like setValueForKeyPath($array, 1, 'campaigns.pushMessages.sentDate'); Commented May 5, 2013 at 21:18

3 Answers 3

5

You can use :

$array = [
        "ID",
        "UUID",
        "pushNotifications.sent",
        "campaigns.boundDate",
        "campaigns.endDate",
        "campaigns.pushMessages.sentDate",
        "pushNotifications.tapped"
];

// Build Data
$data = array();
foreach($array as $v) {
    setValue($data, $v, 1);
}

// Get Value
echo getValue($data, "campaigns.pushMessages.sentDate"); // output 1

Function Used

function setValue(array &$data, $path, $value) {
    $temp = &$data;
    foreach(explode(".", $path) as $key) {
        $temp = &$temp[$key];
    }
    $temp = $value;
}

function getValue($data, $path) {
    $temp = $data;
    foreach(explode(".", $path) as $ndx) {
        $temp = isset($temp[$ndx]) ? $temp[$ndx] : null;
    }
    return $temp;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Ah, and now I understand it. :D Walks into the array with the pointer, then set when there is no deeper. Nice solution, I could hardly find out such a simple one.
You might also want to consider Example 8 in SuperVariable which has object support and Implementing MongoDB-like Query expression object evaluation for other flexible way of working with array
1
function keyset(&$arr, $keypath, $value = NULL)
{
   $keys = explode('.', $keypath);
   $current = &$arr;
   while(count($keys))
   {
      $key = array_shift($keys);
      if(!isset($current[$key]) && count($keys))
      {
         $current[$key] = array();
      }
      if(count($keys))
      {
         $current = &$current[$key];
      }
   }
   $current[$key] = $value;
}

function keyget($arr, $keypath)
{
   $keys = explode('.', $keypath);
   $current = $arr;
   foreach($keys as $key)
   {
      if(!isset($current[$key]))
      {
         return NULL;
      }
      $current = $current[$key];
   }
   return $current;
}

//Testing code:
$r = array();
header('content-type: text/plain; charset-utf8');
keyset($r, 'this.is.path', 39);
echo keyget($r, 'this.is.path');
var_dump($r);

It's a little rough, I can't guarantee it functions 100%.

Edit: At first you'd be tempted to try to use variable variables, but I've tried that in the past and it doesn't work, so you have to use functions to do it. This works with some limited tests. (And I just added a minor edit to remove an unnecessary array assignment.)

Comments

0

In the meanwhile, I came up with (another) solution:

private function setValueForKeyPath(&$array, $value, $keyPath)
{
    $keys = explode(".", $keyPath, 2);
    $firstKey = $keys[0];
    $remainingKeys = (count($keys) == 2) ? $keys[1] : null;
    $isLeaf = ($remainingKeys == null);

    if ($isLeaf)
        $array[$firstKey] = $value;
    else
        $this->setValueForKeyPath($array[$firstKey], $value, $remainingKeys);
}

Sorry for the "long" namings, I came from the Objective-C world. :) So calling this on each keyPath, it actually gives me the output:

fields
Array
(
    [0] => ID
    [1] => UUID
    [2] => pushNotifications.sent
    [3] => campaigns.boundDate
    [4] => campaigns.endDate
    [5] => campaigns.pushMessages.endDate
    [6] => pushNotifications.tapped
)
dissectedFields
Array
(
    [ID] => 1
    [UUID] => 1
    [pushNotifications] => Array
        (
            [sent] => 1
            [tapped] => 1
        )

    [campaigns] => Array
        (
            [boundDate] => 1
            [endDate] => 1
            [pushMessages] => Array
                (
                    [endDate] => 1
                )

        )

)

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.