so long story short - unsetting works fine when trying to unset $this->models[$modelKey] in first foreach, $this->models[$modelKey]->equipmentList->equipment[$eqKey] points to the correct object, but unsetting it in nested foreach doesn't work. Any ideas? Thanks in advance for help.
public function processModelsEquipmentList() {
foreach ($this->models as $modelKey => $model) {
if (!strstr('#', $model->id)) {
foreach ($model->equipmentList->equipment as $eqKey => $equipment) {
if (in_array($equipment->code, $this->specialVersionsCodes)) {
$newModel = clone $model;
$newModel->name.= ' ' . $equipment->name;
$newModel->id.= '#' . $equipment->id;
if (strlen($newModel->code) < 4) {
$newModel->code.=$equipment->code;
}
$newModel->order = $newModel->order + 1;
$newEquipmentList = new EquipmentList($newModel->id, true);
$newEquipmentList->add(clone $equipment);
$newModel->setNewEquipmentList($newEquipmentList);
$this->addModel($newModel);
//echo $this->models[$modelKey]->equipmentList->equipment[$eqKey]->name;die();
unset($this->models[$modelKey]->equipmentList->equipment[$eqKey]);
}
}
}
}
}
isn't it accessed via $model and not $this->models? And with $equipment the same.
Just try this:
unset($equipment[$eqKey]);
Some expansion:
foreach ($this->models as $modelKey => $model) {
//here you use $model to access $this->models[X]
foreach ($model->equipmentList->equipment as $eqKey => $equipment) {
//here you use $equipment to access $this->models[X]->equipmentList->equipment[x]
}
}
EDIT:
Now I got the solution:
foreach ($this->models as $modelKey => $model) {
foreach ($model->equipmentList->equipment as $eqKey => $equipment) {
//use the $modelKey key and not the $eqKey
unset($model->equipmentList->equipment[$modelKey]);
}
}
In case I'm spot on, I'll make this an answer, but if I'm wrong, I'll move this to a comment:
First, you clone the object you are trying to unset at the end. Why not just unset it right after the clone?
Second, I think that object is passed by reference to the foreach loop by design, so you don't need to reference the key.
If I'm right, this might work:
public function processModelsEquipmentList() {
foreach ($this->models as $modelKey => $model) {
if (!strstr('#', $model->id)) {
foreach ($model->equipmentList->equipment as $eqKey => $equipment) {
if (in_array($equipment->code, $this->specialVersionsCodes)) {
$newModel = clone $model;
unset($model); // <-- Unesetting after clone, using loop var name.
$newModel->name.= ' ' . $equipment->name;
$newModel->id.= '#' . $equipment->id;
if (strlen($newModel->code) < 4) {
$newModel->code.=$equipment->code;
}
$newModel->order = $newModel->order + 1;
$newEquipmentList = new EquipmentList($newModel->id, true);
$newEquipmentList->add(clone $equipment);
$newModel->setNewEquipmentList($newEquipmentList);
$this->addModel($newModel);
}
}
}
}
}
Related
I have a foreach loop, in which I loop through the array. I want to add elements as I go through it and have new ones go through it as well.
Now with this code it only does the iterations that I have in the array at the beginning (1 in this case).
Can somebody help me
Thanks
public static function getDirectoriesChilds($id_parent, $parents_array) {
$session_client = Client::getSessionClient();
array_push($parents_array, $id_parent);
$parents_array = array_unique($parents_array);
foreach ($parents_array as $element) {
$childs = Directory::where('id_parent' , '=', $element)->get();
foreach ($childs as $child) {
if ($child->deleted == Controller::DISABLED) {
array_push($parents_array, $child->id);
$parents_array = array_unique($parents_array);
}
}
}
return $parents_array;
}
If changes foreach to for works.
for($i=0; $i<count($parents_array); $i++){
I have a multi-dimensional array with key value pairs. Some of the values of the keys are arrays, and some of the values in that array are arrays as well. It is only 3 branches deep (for now), but I am trying to recursively loop through the array, save the key for each level of the branch, and create a new array when it reaches a string that also mimics the structure of the original array. When it reaches a string, there should be a new object instantiation for each value.
The code below sort of does this, but only creates a flat array.
foreach ($data as $key => $value) {
if (!is_array($value)) {
$a_objects[$key] = new Component([$key], $value);
} else {
foreach ($value as $valueKey => $valueValue) {
if (!is_array($valueValue)) {
$a_objects[$key . "_" . $valueKey] = new Component([$key, $valueKey], $valueValue);
} else {
foreach ($valueValue as $k => $v) {
$a_objects[$key . "_" . $valueKey . "_" . $k] = new Component([$key, $valueKey, $k], $v);
}
}
}
}
Here is my own best attempt at this but it does not seem to save into the b_objects after some testing it does not seem to be saving the object instances.
$b_objects = [];
function create_r($data, $id)
{
foreach ($data as $key => $value) {
if (is_array($value) == true) {
array_push($id, $key);
create_r($value, $id);
} else {
array_push($id, $key);
$b_objects[$key] = new Component($id, $value);
$id = [];
}
}
}
$id = [];
create_r($data, $id);
echo "this is b_objects";
echo "<pre>";
print_r($b_objects);
echo "</pre>";
I verified that $id array contains the right "keys". I feel like this solution is pretty close but I have no idea how to use my $id array to mimic the structure of the $data.
I want to be able to say $b_objects[$level1key][$level2key][$level3key]...[$leveln-1key] = new Component...
Thanks!
I suggest you pass $b_objects by reference to your create_r() function. Otherwise each function call will instantiate a new $b_objects variable which is not used anywhere in the code afterwards.
Passing by reference allows the function to actually change the input array. Notice the & sign in the function declaration.
function create_r($data, $id, &$res)
{
foreach ($data as $key => $value) {
if (is_array($value) == true) {
array_push($id, $key);
create_r($value, $id, $res);
} else {
array_push($id, $key);
$res[$key] = new Component($id, $value);
$id = [];
}
}
}
$id = [];
$b_objects = [];
create_r($data, $id, $b_objects);
I have an array of objects
[new BalanceSheet('2018', '356743', '-56913', '189632', '122733'),
new BalanceSheet('2018', '4562343', '236913', '198732', '6552733'),
new BalanceSheet('2017', '2234643', '55913', '19435342', '855342733')
]
And i need to throw an exception when the first key in object are duplicate another -> 2018 === 2018
I understand how i can to get the key
class BalanceSheet {
public function __construct(string $year, ...) {
$this->year = $year;
...
}
public function getYear() {
return $this->year;
}
private function isDuplicateData($sheets) {
foreach ($sheets as $key => $sheet) {
echo $key . ' year = ' . $sheet->getYear();
}
}
but i don't understand what the easiest way to compare keys in isDuplicateData
If all you need to do is throw an exception, then maybe create an array of the keys and apply array_unique().
private function isDuplicateData($sheets) {
$keys = [];
foreach ($sheets as $key => $sheet) {
$keys[]=$key;
}
if (count($keys) != count(array_unique($keys)){
//throw exception
}
}
How about using php array_filter:
$objects = array(
new BalanceSheet('2018', '356743', '-56913', '189632', '122733'),
new BalanceSheet('2018', '4562343', '236913', '198732', '6552733'),
new BalanceSheet('2017', '2234643', '55913', '19435342', '855342733'),
);
$known = array();
$filtered = array_filter($objects, function ($val) use (&$known) {
// In your case the key would be years
$unique = !in_array($val->years, $known);
$known[] = $val->years;
return $unique;
});
You can compare length of array and length of array_diff.
count($arrayA) == count(array_diff($arrayA,$arrayB));
If you want to delete duplicates you can use the PHP function array_unique, this will check for the duplicates and delete them:
array_unique ( $sheets );
If you want to throw an exception only, you can extract and add the years to another array then check if there are any duplicates:
private function isDuplicateData($sheets) {
$isdublicate = array();
foreach ($sheets as $key => $sheet) {
echo $key . ' year = ' . $sheet->getYear();
$isdublicate[] = $sheet->getYear();
}
for ($i = 0; $i < count($isdublicate); $i++)
{
if ($isdublicate[abs($isdublicate[$i])] >= 0)
$isdublicate[abs($isdublicate[$i])] = -$isdublicate[abs($isdublicate[$i])];
else
//Here throw the exception
}
}
The above for loop logic is here.
I've been working on some code today where I got stuck at a little multidimensional array problem. First of all it's maybe handy to read some code I wrote to get a better view on the problem itself:
public function treeLeaves(array $elements, $parent = 0) {
$branch = array();
foreach($elements as $element) {
$leaf = array('pageid' => $element['pageid'],
'page_parent' => $element['page_parent'],
'label' => ucfirst($element['page_print'][0]['print_title']),
'uri' => $element['page_alias']);
if($element['page_parent'] == $parent) {
$children = $this->treeLeaves($elements, $leaf['pageid']);
if($children) {
foreach($children as $key => $child) {
$leaf['pages'][] = $children[$key];
}
}
$branch[] = $leaf;
}
}
return $branch; }
For some reason I can't figure out how to glue the parent URI alias onto all the separate child URIs. The desired result I'm looking for should look something like this: http://pastebin.com/Eh9ExBjG
I hope some master can help me out here. I've been trying so many different stuff, but can't figure this thing out, even though I feel that it is relatively easy to solve.
Somewhat simplified, but I think you would get the idea:
function treeLeaves($elements, $parent = 0, $baseUri = '/index') {
$branch = array();
foreach($elements as $element) {
if ($element['page_parent'] == $parent) {
$leaf = array(
'uri' => $baseUri . '/' . $element['page_alias'];
);
$leaf['pages'] = treeLeaves($elements, $element['pageid'], $leaf['uri']);
$branch[] = $leaf;
}
}
return $branch;
}
I've written this piece of code, which outputs the profile_display_fields for the $USER:
$appearance = profile_display_fields($USER->id);
if (empty($appearance)) {
//Do nothing
} else {
foreach ($appearance as $c) {
$custom .= '<a href=\''.$CFG->wwwroot.'/course/view.php?id='.$c->id.'\'>'.$c->fullname.'</a>';
}
}
Here is the function I'm using:
function profile_display_fields($userid) {
global $CFG, $USER;
if ($categories = get_records_select('user_info_category', '', 'sortorder ASC')) {
foreach ($categories as $category) {
if ($fields = get_records_select('user_info_field', "categoryid=$category->id", 'sortorder ASC')) {
foreach ($fields as $field) {
require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
$newfield = 'profile_field_'.$field->datatype;
$formfield = new $newfield($field->id, $userid);
if ($formfield->is_visible() and !$formfield->is_empty()) {
print_row(s($formfield->field->name.':'), $formfield->display_data());
}
}
}
}
}
}
What I'm looking to do is try some var_dumps to output the correct data.
However can anyone help me identify the variables?
In your function you are not returning any value but above that in your code, you have assigned a variable to this function:
$appearance = profile_display_fields($USER->id);
You need to return some variable/data from the function and that is the one to be var dumped.
I suppose you are using the print_row to print the data, not returning the response to be used out of the function.