views:

67

answers:

4

I have an array which looks like this

$dataArray = array (
  0 => 
  array (
    'UserId' => '804023',
    'ProjectCode' => 'RA1234',
    'Role' => 'PI',
  ),
  1 => 
  array (
    'UserId' => '804023',
    'ProjectCode' => 'RA1234',
    'Role' => 'PM',
  ),
  2 => 
  array (
    'UserId' => '804023',
    'ProjectCode' => 'A90123',
    'Role' => 'CI',
  ),
  3 => 
  array (
    'UserId' => '804023',
    'ProjectCode' => 'A20022',
    'Role' => 'PM',
  ),
)

I need it to look like this

$expected = array (
  804023 => 
  array (
    'RA1234' => 
    array (
      0 => 'PI',
      1 => 'PM',
    ),
    'A90123' => 
    array (
      0 => 'PI',
    ),
    'A20022' => 
    array (
      0 => 'CI',
    ),
  ),
)

I think this could be achieved generically using recursion as this is a scenario I am likely to come across many times

I have got this far passing in an array of keys that form the nested array keys i.e.

$keys=array("UserId","projectCode","Role");

but am just not seeing where to go from here any pointers?

public function structureData(array $data, array $keys)
 {
  //$structuredData = array();


  foreach ($data as $key => $value)
  {
   $keyForData = array_slice($keys,0,1);


   $remainingKeys = $keys;
   array_shift($remainingKeys);

   if (!array_key_exists($value[$keyForData[0]], $structuredData))
   {

    $count=count($remainingKeys);


    $structuredData[$value[$keyForData[0]]] =array();
    // this returns as expected array(804023 =>array ()); but subsequent recursive calls with the remaining data fail



   }

  }
  return $structuredData);
}
+3  A: 

You don't need recursion, just a loop:

foreach ($dataArray as $da) {
    $expected[$da['UserId']][$da['ProjectCode']][] = $da['Role'];
}

var_export($expected);

/* output:

array (
  804023 => 
  array (
    'RA1234' => 
    array (
      0 => 'PI',
      1 => 'PM',
    ),
    'A90123' => 
    array (
      0 => 'CI',
    ),
    'A20022' => 
    array (
      0 => 'PM',
    ),
  ),
)

*/
webbiedave
That's not everything he needs, but it's the right idea.
Borealid
thanks, I just need to generalize it now
Shaun Hare
It should be everything he needs to get him going in the right direction.
webbiedave
@shaunhare.co.uk: You're welcome. Glad to help.
webbiedave
A: 

Recursion? Nah. Try this:

function add_role($dataArray, $userid, $project_code, $role)
{
    $dataArray[$userid][$project_code][] = $role;
}
A: 

Functional solution:

$t = array_gather_key($dataArray, function ($e) { return $e['UserId']; } );

$t = array_map(
    function ($e) {
        return array_gather_key($e,
            function ($e) { return $e['ProjectCode'];  },
            function ($e) { return $e['Role']; } );
     },
     $t
);

With this higher-order function:

function array_gather_key($array, $func, $transf = null) {
    $res = array();
    foreach ($array as $elem) {
        $key = $func($elem);
        if (!array_key_exists($key, $res))
            $res[$key] = array();
        if ($transf === null)
            $res[$key][] = $elem;
        else
            $res[$key][] = $transf($elem);
    }
    return $res;
}

This gives:

array(1) {
  [804023]=>
  array(3) {
    ["RA1234"]=>
    array(2) {
      [0]=>
      string(2) "PI"
      [1]=>
      string(2) "PM"
    }
    ["A90123"]=>
    array(1) {
      [0]=>
      string(2) "CI"
    }
    ["A20022"]=>
    array(1) {
      [0]=>
      string(2) "PM"
    }
  }
}
Artefacto
A: 

A crude but functioning solution.

function structureData($data, $keys){                                           
    $out = array();                                                             
    foreach($data as $row){                                                     
        $subout = &$out;                                                        
        foreach(array_slice($keys, 0, -1) as $key){                             
            $value = $row[$key];                                                
            $subout = &$subout[$value];                                         
        }                                                                       
        $subout[] = $row[$keys[count($keys) - 1]];                              

    }                                                                           
    return $out;                                                                
}                                                                               

print_r(structureData($dataArray, array('UserId', 'ProjectCode', 'Role')));     
WoLpH
Worked a treat for our scenario thanks
Shaun Hare