I have some difficulties to merge many multidimensional array in php. I tried to do it by many way, but each time, I don't get the result wanted. I tried with array_merge(array_unique,...) and in different post I found a way with array_map, but I don't understand everything...
I can have many multi array like below:
array(
(int) 0 => array(
'User' => array(
'username' => 'testje',
'firstname' => 'jean',
'lastname' => 'test'
),
'Calendar' => array(
'period' => 'AM'
),
'Shift' => array(
'name' => 'HV',
'color' => '#b7fa00'
),
'Team' => array(
'name' => 'Proxy_B28'
)
),
(int) 1 => array(
'User' => array(
'username' => 'testje',
'firstname' => 'jean',
'lastname' => 'test'
),
'Calendar' => array(
'period' => 'PM'
),
'Shift' => array(
'name' => 'HV',
'color' => '#b7fa00'
),
'Team' => array(
'name' => 'Proxy_B28'
)
)
)
And I would like to get this kind of array :
array(
'User' => array(
'username' => 'testje',
'firstname' => 'jean',
'lastname' => 'test'
),
'Calendar' => array(
'period' => 'Full day'
),
'Shift' => array(
'name' => 'HV',
'color' => '#b7fa00'
),
'Team' => array(
'name' => 'Proxy_B28'
)
)
Do you have some advices to give me to get this result ?
Thank you very much !
I don't know if the best solution but it seems to work like this, and fastly :
foreach ($users as $k=>$v){
//$r[$k] = array_merge($v,$users[$k]);
//$unique[] = array_map("unserialize", array_unique(array_map("serialize", $users[$k])));
$s[$k] = array(
'username' => $v['User']['username'],
'team' => $v['Team']['name'],
'period' => $v['Calendar']['period']
);
if ($k > 0) {
if (in_array($v['User']['username'],$s[$k])) {
unset($s[$k-1]);
$s[$k] = array(
'username' => $v['User']['username'],
'team' => $v['Team']['name'],
'period' => "FD"
);
}
}
}
Do you have another idea or this one is enough good ?
thank you !
Related
I would like to replace keys in arrays, because I will move them on two indexes up.
Problem that I am facing is that those are containing same names which will not be ok, if i want to move them up.
This is how array looks like.
$list = array(
'ind' => array(
'messagetype' => 'Alert',
'visibility' => 'Public',
'info' => array(
0 => array(
'urgency' => 'Urgent',
'params' => array(
0 => array(
'Name' => 'display',
'value' => '3; top',
),
1 => array(
'Name' => 'level',
'value' => '1; blue',
),
),
'area' => array(
'ard' => 'Bob',
'code' => array(
0 => array(
'Name' => 'Badge',
'value' => 'GSSD154',
),
),
),
),
1 => array(
'messagetype' => 'Information',
'visibility' => 'Private',
'info' => array(
0 => array(
'urgency' => 'Minor',
'params' => array(
0 => array(
'Name' => 'display',
'value' => '1; left',
),
1 => array(
'Name' => 'level',
'value' => '1; red',
),
),
'area' => array(
'ard' => 'Bob',
'code' => array(
0 => array(
'Name' => 'Badge',
'value' => 'GBECS23',
),
),
),
),
),
),
),
),
);
and this is how I would like the output to be with changing keys in Name0, Name1, which are inside params.
$list = array(
'ind' => array(
'messagetype' => 'Alert',
'visibility' => 'Public',
'info' => array(
0 => array(
'urgency' => 'Urgent',
'params' => array(
0 => array(
'Name0' => 'display',
'value0' => '3; top',
),
1 => array(
'Name1' => 'level',
'value1' => '1; blue',
),
),
'area' => array(
'ard' => 'Bob',
'code' => array(
0 => array(
'Name' => 'Badge',
'value' => 'GSSD154',
),
),
),
),
1 => array(
'messagetype' => 'Information',
'visibility' => 'Private',
'info' => array(
0 => array(
'urgency' => 'Minor',
'params' => array(
0 => array(
'Name0' => 'display',
'value0' => '1; left',
),
1 => array(
'Name1' => 'level',
'value1' => '1; red',
),
),
'area' => array(
'ard' => 'Bob',
'code' => array(
0 => array(
'Name' => 'Badge',
'value' => 'GBECS23',
),
),
),
),
),
),
),
),
);
I have tried with a lots of examples over this website, but could not find one to achieve this.
Code that I used from
How to replace key in multidimensional array and maintain order
function replaceKey($subject, $newKey, $oldKey) {
// if the value is not an array, then you have reached the deepest
// point of the branch, so return the value
if (!is_array($subject)) {
return $subject;
}
$newArray = array(); // empty array to hold copy of subject
foreach ($subject as $key => $value) {
// replace the key with the new key only if it is the old key
$key = ($key === $oldKey) ? $newKey : $key;
// add the value with the recursive call
$newArray[$key] = replaceKey($value, $newKey, $oldKey);
}
return $newArray;
}
$s = replaceKey($list, 'Name0', 'Name');
print "<PRE>";
print_r($s);
at the moment I get this output:
[0] => Array
(
[Name0] => display
[value] => 1; left
)
[1] => Array
(
[Name0] => level
[value] => 1; red
)
any help would be appreciated. regards
A very strange question, but why not?
The following function returns nothing (a procedure) and changes the array in-place using references but feel free to rewrite it as a "real" function (without references and with a return statement somewhere).
The idea consists to search for arrays, with numeric keys and at least 2 items, in which each item has the Name and value keys. In other words, this approach doesn't care about paths where the targets are supposed to be:
function replaceKeys(&$arr) {
foreach ($arr as &$v) {
if ( !is_array($v) )
continue;
$keys = array_keys($v);
if ( count($keys) < 2 ||
$keys !== array_flip($keys) ||
array_keys(array_merge(...$v)) !== ['Name', 'value'] ) {
replaceKeys($v);
continue;
}
foreach ($v as $k => &$item) {
$item = array_combine(["Name$k", "value$k"], $item);
}
}
}
replaceKeys($list);
print_r($list);
demo
I cant use a join to get the required data from the table relationship of
Student HABTM Subject, and
Guardian 1 to many Student
Without giving all the code,my find gets the required data but it adds another table (AvailabilityForStudent)which has a HABTM relationship with Student, along with other fields. I simply get too much data.
I have to add Guardian2 to the Guardian table to avoid a conflict which i dont understand.
What is the correct join to display data from 3 tables only?
$students = $this->find('all', array(
'joins'=>$joins,
'conditions' => $conditions,
'fields'=> $fields,
'order'=>$order,
));
$joins = array(
array('table' => 'students_subjects',
'alias' => 'StudentsSubject',
'type' => 'LEFT',
'conditions' => array(
'Student.id=StudentsSubject.student_id',
)
),
array('table' => 'subjects',
'alias' => 'Subject',
'type' => 'LEFT',
'conditions' => array(
'StudentsSubject.subject_id=Subject.id',
)
),
array('table' => 'guardians',
'alias' => 'Guardian2',
'type' => 'LEFT',
'conditions' => array(
'Student.guardian_id=Guardian2.id',
)
),
);
(int) 0 => array(
'Student' => array(
'id' => '267',
'last_name' => 'xxx',
'first_name' => 'xxx',
'address_suburb' => 'xxx',
'student_inactive' => false,
'student_mobile' => '0'
),
'Guardian' => array(
'guardian_last_name' => 'xx',
'guardian_first_name' => 'xxxx',
'id' => '267',
'guardian_mobile' => 'xxxx',
'guardian_email' => 'xx#yahoo.com.au'
),
'Subject' => array(
'name' => 'English: Year 7 - 10',
(int) 0 => array(
'id' => '9',
'name' => 'English: Year 7 - 10',
'StudentsSubject' => array(
'id' => '1079',
'student_id' => '267',
'subject_id' => '9',
'created' => null,
'modified' => null
)
)
),
'StudentsSubject' => array(
'id' => '1079'
),
'AvailabilityForStudent' => array(
(int) 0 => array(
Update- added this line $this->recursive = -1 instead of $this->Student->recursive = -1; and it works
Update- added this line $this->recursive = -1 instead of $this->Student->recursive = -1; and it works
I have a HABTM relationship of Students and Subjects. I simply want to display all the subjects associated with a student without repetition of student details. I dont want the student details to keep repeating in the data output. How do I get the student details as shown below to output once and then all the subjects associated with this student to output?
Group didnt work. I didnt see the answer in the docs but I am sure this is a simple task to do.
http://book.cakephp.org/2.0/en/models/retrieving-your-data.html
$this->Student->recursive = -1;
$joinoptions = array(
// $options['joins'] = array(
array('table' => 'students_subjects',
'alias' => 'StudentsSubject',
'type' => 'LEFT',
'conditions' => array(
'Student.id = StudentsSubject.student_id',
)
),
array('table' => 'subjects',
'alias' => 'Subject',
'type' => 'LEFT',
'conditions' => array(
'StudentsSubject.subject_id=Subject.id',
)
),
);
$fieldoptions = array('Student.id,Student.last_name,Student.first_name,Student.address_street,Student.address_suburb,'
. 'Subject.name,Subject.id, StudentsSubject.id, Student.first_name,Student.last_name,Student.address_lat,Student.address_long,Student.tutor_gender_preference'
);
$student=$this->Student->find('all',array(
'conditions'=> array( 'Student.id' => $student_id),
'fields'=>$fieldoptions,
'joins'=> $joinoptions,
// 'group' => 'Student.id',
'recursive' =>-1,
));
array(
(int) 0 => array(
'Student' => array(
'id' => '216',
'last_name' => 'Ncc',
'first_name' => 'Acc',
'address_street' => '8 sdsdt',
'address_suburb' => 'Hasdsdk',
'address_lat' => 'xx',
'address_long' => 'xx',
'tutor_gender_preference' => 'No Preference'
),
'Subject' => array(
'name' => 'English: Year 7 - 10',
'id' => '9'
),
'StudentsSubject' => array(
'id' => '531'
)
),
(int) 1 => array(
'Student' => array(
'id' => '216',
'last_name' => 'Ncc',
'first_name' => 'Acc',
'address_street' => '8 sdsdt',
'address_suburb' => 'Hasdsdk',
'address_lat' => 'xx',
'address_long' => 'xx',
'tutor_gender_preference' => 'No Preference'
),
'Subject' => array(
'name' => 'Maths: Year 7 - 10',
'id' => '16'
),
'StudentsSubject' => array(
'id' => '532'
)
),
(int) 2 => array(
'Student' => array(
'id' => '216',
'last_name' => 'Ncc',
'first_name' => 'Acc',
'address_street' => '8 sdsdt',
'address_suburb' => 'Hasdsdk',
'address_lat' => 'xx',
'address_long' => 'xx',
'tutor_gender_preference' => 'No Preference'
),
'Subject' => array(
'name' => 'Physics: Year 11',
'id' => '28'
),
'StudentsSubject' => array(
'id' => '583'
)
)
)
I'm using containable behavior and the result of my find('all') is:
array(
(int) 0 => array(
'User' => array(
'id' => '106',
'email' => 'daje#daje.it',
'pwd' => '0433c024cb08be13000d59a347e640482843f46f177e95749dc6599c259617fd3491dcb940b47693cbbc7f65a2cc5ef62deca2e600c1be133ad54170f7d1fbd1',
'role_id' => '3',
'active' => '1'
),
'Lead' => array(
'id' => '6'
),
'Estimate' => array(
(int) 0 => array(
'lead_id' => '6',
'Estimate' => array(
(int) 0 => array(
'TOT_count' => '2'
)
)
)
)
)
)
I need to to count how many estimates there are in the lead.
The total (2) is correct, but i see nested 'Estimated' array, why ?
The result i would like to get is:
array(
(int) 0 => array(
'User' => array(
'id' => '106',
'email' => 'daje#daje.it',
'pwd' => '0433c024cb08be13000d59a347e640482843f46f177e95749dc6599c259617fd3491dcb940b47693cbbc7f65a2cc5ef62deca2e600c1be133ad54170f7d1fbd1',
'role_id' => '3',
'active' => '1'
),
'Lead' => array(
'id' => '6'
),
'Estimate' => array(
'TOT_count' => '2'
)
)
)
This is the find:
$options = array(
'contain' => array(
'User',
'Estimate' => array(
'fields' => 'COUNT(*) AS TOT_count'
)
),
'conditions' => array('Lead.id' => 6),
'fields' => 'User.*',
'limit' => 1
);
debug($this->Lead->find('all', $options));
How can i do it?
Thanks!
When you use a "custom" AS statement, in your case TOT_count, Cake will always put this in a result key called 0. You can avoid this by defining TOT_count as a virtualField in your model. That way it will be nested directly under the model name in your resultset.
Secondly, the lead_id is forcedly retrieved, because it is "needed" to make the join with the Lead model. It can not properly retrieve all the data without that piece of information there.
How to transform an array below to a nested array?
Please, see expected result code.
By the way, in my real application I'm using SHA-1 hash values as keys & parent keys.
So, all keys are unique.
Thanks.
$arr = array(
array(
'key' => 'apple',
'parent_key' => 'root',
'name' => '1'
),
array(
'key' => 'banana',
'parent_key' => 'root',
'name' => '2'
),
array(
'key' => 'sun',
'parent_key' => 'apple',
'name' => '1.1'
),
array(
'key' => 'moon',
'parent_key' => 'root',
'name' => '3'
),
array(
'key' => 'mars',
'parent_key' => 'sun',
'name' => '1.1.1'
)
);
Expected result:
$arr = array(
array(
'key' => 'apple',
'parent_key' => 'root',
'children' => array(
'key' => 'sun',
'parent_key' => 'apple',
'name' => '1.1',
'children' => array(
'key' => 'mars',
'parent_key' => 'sun',
'name' => '1.1.1'
)
)
),
array(
'key' => 'banana',
'parent_key' => 'root',
'name' => '2'
),
array(
'key' => 'moon',
'parent_key' => 'root',
'name' => '3'
)
);
foreach($initial_array as $subarray){
if($subarray['parent_key'] == 'root'){
$final_array[$subarray['key']] = $subarray;
}else{
$final_array[$subarray['parent_key']]['children'][$subarray['key']] = $subarray;
}
}
The only thing here is that, looking at your example, this code can only handle a depth of one. If you have a 'parent_key' => 'sun', for example, this will not work.