How to dynamically set array keys in php

I have some logic that is used to sort data, but depending on user input, the data is grouped differently. Right now I have five different functions that contain the same logic, but different groups. Is there a way to combine these functions and dynamically set the value to be grouped correctly. Inside the function, these assignments occur

For example, sometimes I store calculations simply:

$calcs[$meter['UnitType']['name']] = ... 

but in other cases a more specific grouping is required:

 $calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] =... 

As you can see, sometimes it is stored in a multidimensional array, and in other cases not. I am trying to use eval (), but to no avail (not sure if this is the right approach). Storing data in a temporary variable actually saves little, because there are many nested loops and if statements, so the array must be repeated in several places.

EDIT

Hope the following example will explain my problem better. This is obviously a dead end version:

 if(){ $calcs[$meter['UnitType']['name']] = $data; } else { while () { $calcs[$meter['UnitType']['name']] = $data; } } 

Now you can use the same logic, but to store it in different keys:

 if(){ $calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data; } else { while () { $calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data; } } 

Is there a way to abstract the keys in the $ calc [] array to have one function instead of multiple functions with different array keys?

+9
arrays eval php multidimensional-array
source share
6 answers

Wouldn't it be easier to do the following

 $calcs = array( $meter['Resource']['name'] => array( $meter['UnitType']['name'] => 'Some Value', $meter['UnitType']['name2'] => 'Some Value Again' ), ); 

or you can use objects

 $calcs = new stdClass(); $calcs->{$meter['UnitType']['name']} = 'Some Value'; 

but I would advise you to build your structure in arrays and then do it!

 $calcs = (object)$calcs_array; 

or you can loop your first array into a new array!

 $new = array(); $d = date('Y-m',$start); foreach($meter as $key => $value) { $new[$key]['name'][$d] = array(); } 

Give it back and see how the structure of the array comes out.

0
source share

Try using a switch enclosure.

 <?php $userinput = $calcs[$meter['UnitType']['name']] = $data;; switch ($userinput) { case "useriput1": while () { $calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data; } break; case "userinput2": while () { $calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data; } break; ... default: while () { $calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data; } } ?> 
0
source share

I agree with the comment on OP by @Jake N that perhaps using objects is a better approach. However, if you want to use arrays, you can check for the keys in the conditional expression, for example:

 if( array_key_exists('Resource', $meter) ) { $calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data; } else { $calcs[$meter['UnitType']['name']] = $data; } 

On the other hand, if you want to use objects, you can create a MeterReading object MeterReading , and then add MeterReading instances as array elements to the $calcs , for example:

 // Object defintion class MeterReading { private $data; private $resource; private $startDate; private $unitType; public function __construct(Array $meter, $start, $data) { $this->unitType = $meter['UnitType']['name']; $this->resource = $meter['Resource']['name']; $this->startDate = date('Y-m',$start); } public function data() { return $this->data; } public function resource() { return $this->resource; } public function startDate() { return $this->startDate; } public function unitType() { return $this->unitType; } } // Example population $calcs[] = new MeterReading($meter, $start, $data); // Example usage foreach($calcs as $calc) { if($calc->resource()) { echo 'Resource: ' . $calc->resource() . '<br>'; } echo 'Unit Type: ' . $calc->unitType() . '<br>'; echo 'Start Date: ' . $calc->startDate() . '<br>'; echo 'Data: ' . $calc->data() . '<br>'; } 

Obviously, you can take this further, for example, check for the presence of array keys in the object constructor by providing the default property of the resource object if it is not specified, and so on, but this is the beginning of the OO approach.

0
source share

You can use this if you want to get and set the array values ​​dynamically.

 function getVal($data,$chain){ $level = $data; for($i=0;$i<count($chain);$i++){ if(isset($level[$chain[$i]])) $level = $level[$chain[$i]]; else return null; // key does not exist, return null } return $level; } function setVal(&$data,$chain,$value){ $level = &$data; for($i=0;$i<count($chain);$i++){ $level = &$level[$chain[$i]]; // set reference (&) in order to change the value of the object } $level = $value; } 

How it works:

Calling getVal($data,array('foo','bar','2017-08')) will return the equivalent of $data['foo']['bar']['2017-08'] .

Calling setVal($data,array('foo','bar','2017-08'),'hello') will set the value as if you were calling $data['foo']['bar']['2017-08'] = 'hello' . nonexistent keys will be created automatically using php magic.

This can be useful if you want to dynamically build an array structure.

0
source share

Here is the function I wrote to set deeply nested elements in arrays or objects:

 function dict_set($var, $path, $val) { if(empty($var)) $var = is_array($var) ? array() : new stdClass(); $parts = explode('.', $path); $ptr =& $var; if(is_array($parts)) foreach($parts as $part) { if('[]' == $part) { if(is_array($ptr)) $ptr =& $ptr[]; } elseif(is_array($ptr)) { if(!isset($ptr[$part])) $ptr[$part] = array(); $ptr =& $ptr[$part]; } elseif(is_object($ptr)) { if(!isset($ptr->$part)) $ptr->$part = array(); $ptr =& $ptr->$part; } } $ptr = $val; return $var; } 

Using the example data:

 $array = []; $array = dict_set($array, 'resource1.unit1.2017-10', 'value1'); $array = dict_set($array, 'resource1.unit2.2017-11', 'value2'); $array = dict_set($array, 'resource2.unit1.2017-10', 'value3'); print_r($array); 

Output Results:

 Array ( [resource1] => Array ( [unit1] => Array ( [2017-10] => value1 ) [unit2] => Array ( [2017-11] => value2 ) ) [resource2] => Array ( [unit1] => Array ( [2017-10] => value3 ) ) ) 

The second argument to dict_set() is the $path string in dotted notation. You can build this using dynamic keys with period separators between parts. The function works with arrays and objects.

It can also add incremental elements to a deeply nested array using [] as the $path element. For example: parent.child.child.[]

0
source share

You can use this library to get or set a value in a multidimensional array using an array of keys:

 Arr::getNestedElement($calcs, [ $meter['Resource']['name'], $meter['UnitType']['name'], date('Y-m', $start) ]); 

to get the value or:

 Arr::handleNestedElement($calcs, [ $meter['Resource']['name'], $meter['UnitType']['name'], date('Y-m', $start) ], $data); 

set $data as a value.

0
source share

All Articles