Pushing a sub array into the same array - php

I am trying to put content of one array into the same array. Here I have an array $mclass with values such as
Array
(
[0] => stdClass Object
(
[room_id] => 1,3,5
[day] => 1
[class_teacher] => TEA-2014-2
[final_exam_date] => 2015-09-21
)
)
You can see I have room_id index with 1,3,5 value. Now, I want to explode the room_id and get duplicate of same array index data with change of room_id and push into the array. and finally delete the current array index such as [0]. Here I want the final result as.
Array
(
[0] => stdClass Object
(
[room_id] => 1
[day] => 1
[class_teacher] => TEA-2014-2
[final_exam_date] => 2015-09-21
)
[1] => stdClass Object
(
[room_id] => 3
[day] => 1
[class_teacher] => TEA-2014-2
[final_exam_date] => 2015-09-21
)
[2] => stdClass Object
(
[room_id] => 5
[day] => 1
[class_teacher] => TEA-2014-2
[final_exam_date] => 2015-09-21
)
)
Here is my code for the same:
if(count($mclass)>0)
{
foreach($mclass as $mclasskey=>$mclass_row)
{
/* Room ID Calculation */
if(isset($mclass[$mclasskey]))
{
$temp_room_id = explode(',',$mclass_row->room_id);
if(count($temp_room_id)>1)
{
foreach($temp_room_id as $trkey=>$tr)
{
if(!in_array($temp_room_id[$trkey], $morning_class_semester))
{
array_push($morning_class_semester,$temp_room_id[$trkey]);
}
}
if(count($morning_class_semester)>0)
{
foreach($morning_class_semester as $mcskey=>$mcs)
{
$index_count = count($new_test);
$test[$index_count] = $mclass[$mclasskey];
$test[$index_count]->room_id = $morning_class_semester[$mcskey];
array_push($new_test,$test[$index_count]);
}
unset($mclass[$mclasskey]);
}
}
}
}
}

The code below does what you're looking for using only arrays. So you'll have to change the array access operators to -> since you're accessing an object. I'd do so, but it would break the example, so I'll leave that up to you.
Code Explained:
Loop through array selecting each subarray (object in your case), explode on the $item('room_id') ... ($item->room_id in your case) ... and create sub arrays, via loop, from that using the data from the original using each key. Remove the original item (which has the combined room_ids) and combine the placeholder and original array.
<?php
//Establish some data to work with
$array = array(
array(
"room_id" => "1,3,5",
"day" => 1,
"class_teacher" => "TEA-2014-2",
"final_exam_date" => "2015-09-21",
));
foreach ($array as $key => $item) {
$placeholder = array();
$ids = explode(',',$item['room_id']);
if (count($ids) > 1) {
foreach ($ids as $id) {
$push = array(
'room_id' => $id,
'day' => $item['day'],
'class_teacher' => $item['class_teacher'],
'final_exam_date' => $item['final_exam_date']
);
array_push($placeholder, $push);
}
$array = array_merge($array, $placeholder);
unset($array[$key]);
}
}
var_dump($array);
?>

Related

PHP - combine values from Objectlist with same key

I have an objectlist:
$deliveryOptions =
Array ( [0] => stdClass Object ( [item_id] => 55 [value] => delivery-online )
[1] => stdClass Object ( [item_id] => 55 [value] => delivery-campus )
[2] => stdClass Object ( [item_id] => 56 [value] => delivery-campus )
[3] => stdClass Object ( [item_id] => 81 [value] => delivery-blended )
)
I need to format it to an array:
$combined =
( [item_id] => 55 [course-delivery] => array( "delivery-online","delivery-campus")
( [item_id] => 56 [course-delivery] => delivery-campus )
( [item_id] => 81 [course-delivery] => delivery-blended )
My code so far:
foreach ($deliveryOptions as $row)
{
$temp = array('item_id'=>$row->item_id,
'course-delivery'=>$row->value
);
$course[] = $temp;
}
foreach ($course as $row)
{
$match = array_search($row['item_id'], array_column($combined, 'item_id'));
if(is_numeric($match))
{
$combined[$match]['course-delivery'][] = $row['course-delivery'];
}
else{
array_push($combined, [
'item_id' => $row['item_id'],
'course-delivery' => array($row['course-delivery'])
]);
}
}
The format of $combined might seem odd, but I have three different queries creating different object lists that all need to be combined into one JSON array based on 'item_id' as the key.
I have the part where all three get combined working, this new array configuration comes from a checkbox situation, thus the need to combine the different values off the same item_id.
No need for another foreach, you just create the structure along the way. First, initialize the container for the particular item_id.
When an item_id hits again and is not an array, just overwrite it, use the first value (string) and turn it to an array and finally push the value.
$deliveryOptions = [
(object) ['item_id' => 55, 'value' => 'delivery-online'],
(object) ['item_id' => 55, 'value' => 'delivery-campus'],
(object) ['item_id' => 56, 'value' => 'delivery-campus'],
(object) ['item_id' => 81, 'value' => 'delivery-blended'],
];
$combined = [];
foreach ($deliveryOptions as $row) {
if (!isset($combined[$row->item_id])) { // initialize if it doesn't exist
$combined[$row->item_id] = (array) $row; continue;
}
if (!is_array($combined[$row->item_id]['value'])) { // if another occurence
$temp = $combined[$row->item_id]['value']; // get the string initial value
$combined[$row->item_id]['value'] = []; // turn it into an array
$combined[$row->item_id]['value'][] = $temp; // and reassign and push inside the array
}
$combined[$row->item_id]['value'][] = $row->value; // push the value in the array
}
// $combined = array_values($combined); // array key reindex if needed
Sample output

Group and merge subarray data based on one column value

I have an array in PHP code below, and I want to convert this array to be grouped by data value. It's always hard to simplify arrays.
Original array:
Array
(
[0] => Array
(
[date] => 2017-08-22
[AAA] => 1231
)
[1] => Array
(
[date] => 2017-08-21
[AAA] => 1172
)
[2] => Array
(
[date] => 2017-08-20
[AAA] => 1125
)
[3] => Array
(
[date] => 2017-08-21
[BBB] => 251
)
[4] => Array
(
[date] => 2017-08-20
[BBB] => 21773
)
[5] => Array
(
[date] => 2017-08-22
[CCC] => 3750
)
[6] => Array
(
[date] => 2017-08-20
[CCC] => 321750
)
)
Below is my desired array:
Array
(
[2017-08-22] => Array
(
[AAA] => 1231
[CCC] => 3750
)
[2017-08-21] => Array
(
[AAA] => 1172
[BBB] => 251
)
[2017-08-20] => Array
(
[AAA] => 1125
[BBB] => 21773
[CCC] => 321750
)
)
It is also ok to have empty null value if the data doesn't exist. [BBB] => NULL for 2017-08-22.
Can anybody help? Thanks in advance...
A simple loop should do this..
$group = [];
foreach ($data as $item) {
if (!isset($group[$item['date']])) {
$group[$item['date']] = [];
}
foreach ($item as $key => $value) {
if ($key == 'date') continue;
$group[$item['date']][$key] = $value;
}
}
Here : this should do the work.
$dst_array = array();
foreach ($array as $outerval) {
foreach ($outerval as $key => $innerval) {
if ($key != 'date') {
$dst_array[$outerval['date']][$key] = $innerval;
}
}
}
It iterates through the array and then through the entries in each subarray. Any any that is not a date is assigned in the destination array in the subarray corresponding to its date and with its own current key.
I definitely wouldn't recommend any techniques that involve more than one loop -- this process can certainly be performed in a single loop.
If you like language construct iteration, use a foreach() loop: (Demo)
$result = [];
foreach ($array as $row) {
$date = $row['date'];
unset($row['date']);
$result[$date] = array_merge($result[$date] ?? [], $row);
}
var_export($result);
If you like to use functional programming and fewer global variables, use array_reduce(): (Demo)
var_export(
array_reduce(
$array,
function($accumulator, $row) {
$date = $row['date'];
unset($row['date']);
$accumulator[$date] = array_merge($accumulator[$date] ?? [], $row);
return $accumulator;
},
[]
)
);
These techniques unconditionally push data into the subarray with the key based on the date column value.
The above technique will work consistently even if the order of your subarray elements changes.
The ?? (null coalescing operator) is to ensure that array_merge() always has an array in the first parameter -- if processing the first occurrence of a given date, you simply merge the current iteration's data (what's left of it after unset() removes the date element) with an empty array.
I believe this solution will work for you:
<?php
$array = Array
(
0 => Array
(
'date' => '2017-08-22',
'AAA' => '1231',
),
1 => Array
(
'date' => '2017-08-21',
'AAA' => '1172',
),
2 => Array
(
'date' => '2017-08-20',
'AAA' => '1125'
),
3 => Array
(
'date' => '2017-08-21',
'BBB' => '251'
),
4 => Array
(
'date' => '2017-08-20',
'BBB' => '21773',
),
5 => Array
(
'date' => '2017-08-22',
'CCC' => '3750'
),
6 => Array
(
'date' => '2017-08-20',
'CCC' => '321750'
)
);
echo '<pre>';
$array1 = array('AAA' => null, 'BBB' => null, 'CCC' => null);
$array2 = array();
array_walk($array, function ($v) use (&$array2, $array1) {
$a = $v['date'];
if (!isset($array2[$a])) {
$array2[$a] = $array1;
}
unset($v['date']);
$array2[$a] = array_merge($array2[$a], $v);
});
print_r($array2);
Output
Array
(
[2017-08-22] => Array
(
[AAA] => 1231
[BBB] =>
[CCC] => 3750
)
[2017-08-21] => Array
(
[AAA] => 1172
[BBB] => 251
[CCC] =>
)
[2017-08-20] => Array
(
[AAA] => 1125
[BBB] => 21773
[CCC] => 321750
)
)
check output at: https://3v4l.org/NvLB8
Another approach (quick & dirty) making use of an arrays internal pointer:
$newArray = [];
foreach ($array as $childArray) {
$date = current($childArray);
$value = next($childArray); // this advances the internal pointer..
$key = key($childArray); // ..so that you get the correct key here
$newArray[$date][$key] = $value;
}
This of course only works with the given array structure.
Another perfect usage example for the PHP function array_reduce():
// The input array
$input = array(
0 => array(
'date' => '2017-08-22',
'AAA' => '1231',
),
// The rest of your array here...
);
$output = array_reduce(
$input,
function (array $carry, array $item) {
// Extract the date into a local variable for readability and speed
// It is used several times below
$date = $item['date'];
// Initialize the group for this date if it doesn't exist
if (! array_key_exists($date, $carry)) {
$carry[$date] = array();
}
// Remove the date from the item...
// ...and merge the rest into the group of this date
unset($item['date']);
$carry[$date] = array_merge($carry[$date], $item);
// Return the partial result
return $carry;
},
array()
);
The question is not clear. What is the expected result if one key (AAA f.e) is present on two or more dates? This answer keeps only the last value associated with it.

Combination of arrays

I have tried to get the below code to work for a good couple of hours, but just don't succeed.
I have this date array:
Array ( [0] => Array ( [0] => 2007 )
[1] => Array ( [0] => 2008 )
[2] => Array ( [0] => 2009 )
...
)
and this plusMinus one:
Array ( [0] => Array ( [plus] => 2 [date] => 2007 )
[1] => Array ( [minus] => 1 [date] => 2008 )
[2] => Array ( [minus] => 1 [date] => )
[3] => Array ( [plus] => 1 [date] => 2010 [minus] => 1 )
)
I have been trying to combine them into this:
Array ( [0] => Array ( [date] => 2007 [plus]=> 2)
[1] => Array ( [date] => 2008 [minus]=> 1)
[2] => Array ( [date] => 2009 [plusMinus]=> 0)
[3] => Array ( [date] => 2010 [plus] => 1 [minus]=>1 )
...
)
So basically I want to check if a value of the date array exists in the plusMinus array. If true the date and values from the plusMinus array shall replace the entry in the date array.
If false, the original date array entry is complemented by a [plusMinus] => 0 key-value pair.
The way I have tried to do it is this:
foreach ($filler as $key1 => $value1)
{
foreach ($plusMinus as $key2 => $value2)
{
if ($value1['0'] !== $value2['date'])
{
$value1['plusMinus'] = '0';
$result2[$key1][] = $value1;
}
elseif ($value1['0'] == $value2['date'])
{
if (array_key_exists('plus',$value2))
{
$value1['plus'] = $value2['plus'];
$result2[$key1][]=$value1;
}
elseif(array_key_exists('minus',$value2))
{
$value1['minus'] = $value2['minus'];
$result2[$key1][]=$value1;
}
elseif(array_key_exists('minus',$value2) &&
array_key_exists('plus',$value2))
{
}
}
}
}
$valuesComplete = array();
foreach ($result2 as $value) {
$result2 = $value['0'];
array_push($valuesIncomplete, $result2);
}
return $valuesComplete;
Instead of the desired outcome described above I get this:
Array ( [0] => Array
( [0] => 2007 [plus] => 2 )
[1] => Array ( [0] => 2008 [plusMinus => 0 )
[2] => Array ( [0] => 2009 [plusMinus] => 0 )
[3] => Array ( [0] => 2010 [plusMinus] => 0 )
[4] => Array ( [0] => 2011 [plusMinus] => 0 )
[5] => Array ( [0] => 2012 [plusMinus] => 0 )
[6] => Array ( [0] => 2013 [plusMinus] => 0 )
)
What am I missing? Thanks for any help!
Unfortunately, because of the input data format, I can't see any way to do this that doesn't involve an O(n + m + p) operation. But no matter, you gotta do what you gotta do.
Firstly I would start by filtering the useless elements from the PlusMinus array. Since it's already fairly close to the desired output format, it makes sense to use this as the base of the result.
$temp = array();
foreach ($plusMinus as $item) {
if (!empty($item['date'])) {
$temp[$item['date']] = $item;
}
}
Notice that I used the date as the index of the temporary array we're using to build the result. This is to allow you to easily ensure that the result array is in the correct order, and to quickly check whether an item needs to be added from the Filler array.
Next, we need to add any missing elements from the Filler array:
foreach ($filler as $item) {
if (!isset($temp[$item[0]])) {
$temp[$item[0]] = array(
'date' => $item[0],
'plusMinus' => 0
);
}
}
Now all the data is in the array in the correct format, we just need to sort it:
ksort($temp);
...and get convert it back to an indexed array:
return array_values($temp);
No need for the performance killing nested loops or complex flow control.
See it working
As I understood you need to add years that not in second array but in first?
In that case you can do:
foreach ($filler as $key1 => $value1)
{
$ok = false;
foreach ($plusMinus as $key2 => $value2)
{
if($value2['date']==$value1[0])
{
$ok = true;
break;
}
}
if(!$ok)
{
$plusMinus[$value1[0]]=array('date'=>$value1[0], 'plusMinus'=>0);
}
}
<?php
$a1 = array(array( 2007 ),
array( 2008 )
);
$a2 = array(array('plus'=>1, 'date'=>2007),
array('minus'=>1,'date'=>2008),
array('plus'=>1, 'minus'=>1, 'date'=>2008)
);
$r = array();
foreach($a1 as $k1=>$d1) {
$year = $d1[0];
foreach( $a2 as $k2=>$d2 ) {
if( $d2['date'] == $year ) {
$r[$year]['date'] = $year;
if(isset($d2['plus'])) {
$r[$year]['plus'] = $d2['plus'];
}
if(isset($d2['minus'])) {
$r[$year]['minus'] = $d2['minus'];
}
}
}
}
print_r($r);
and result
Array
(
[2007] => Array
(
[date] => 2007
[plus] => 1
)
[2008] => Array
(
[date] => 2008
[minus] => 1
[plus] => 1
)
)
$ar1 = array( array(2007), array(2008), array(2009), array(2010) );
$ar2 = array(
array("date"=>2007, "plus"=>2),
array("date"=>2008, "minus"=>1),
array("date"=>"", "minus"=>1),
array("date"=>2010, "plus"=>1, "minus"=>1)
);
foreach($ar2 as $key=>$val){
if(isset($ar1[$key][0]))
$val["date"] = $ar1[$key][0];
$ar2[$key] = $val;
}
I am not sure if I understand you correctly but this works fine...
It will work only if you are sure that your both arrays "date" equals one to other..
This is what I came up with:
To not create the product of both arrays (foreach inside foreach), I first index the $plusMinus array with the date. That will allow to test quickly if a year exists or not:
$years = array_combine(array_column($plusMinus, 'date'), $plusMinus);
This uses the array_column() function of PHP 5.5, if you don't have it you can easily create it your own.
After doing that it is exactly how you wrote it in your own words:
foreach($date as &$entry)
{
list($year) = $entry;
$entry = array('date' => $year);
// check if a value of the date array exists in the plusMinus array.
if (isset($years[$year])) {
// If true the date and values from the plusMinus array shall replace the entry in the date array
$entry += $years[$year];
} else {
// If false, the original date array entry is complemented by a [plusMinus] => 0 key-value pair.
$entry += array('plusMinus' => 0);
}
}
unset($entry);
See it i action.
This will work just fine.
I did not at all understand your question, but if i got it this is the way:
First make your $datearray more understandable like this:
$dateArray = array(2007,2008,2009,2010);
$plusMinus = array(
array( 'plus' => 2 ,'date' => 2007),
array( 'minus' => 1 ,'date' => 2008),
array ( 'minus' => 1 , 'date' => '' ),
array ( 'plus' => 1 , 'date' => 2010 , 'minus' => 1 )
);
You can make it multidimensional later;
After that:
foreach($dateArray as $k=>$v)
{
if(in_array($v,$plusMinus[$k]))
{
$filler[$k] = $plusMinus[$k];
}
else{
if(empty($plusMinus[$k]['date']))
{
$filler[$k]['date']= $v;
$filler[$k]['plusMinus'] = 0;
}
}
}
This is simple and clean, understandable way with very little code if your arrays will always have the structure you described, meaning the plusMinus values for 2007 are in the cell [0] and the 2007 in the dateArrays is also in the cell [0] like you have shown. I hope i could help.

Checking if array value exists in a PHP multidimensional array

I have the following multidimensional array:
Array ( [0] => Array
( [id] => 1
[name] => Jonah
[points] => 27 )
[1] => Array
( [id] => 2
[name] => Mark
[points] => 34 )
)
I'm currently using a foreach loop to extract the values from the array:
foreach ($result as $key => $sub)
{
...
}
But I was wondering how do I see whether a value within the array already exists.
So for example if I wanted to add another set to the array, but the id is 1 (so the person is Jonah) and their score is 5, can I add the 5 to the already created array value in id 0 instead of creating a new array value?
So after the loop has finished the array will look like this:
Array ( [0] => Array
( [id] => 1
[name] => Jonah
[points] => 32 )
[1] => Array
( [id] => 2
[name] => Mark
[points] => 34 )
)
What about looping over your array, checking for each item if it's id is the one you're looking for ?
$found = false;
foreach ($your_array as $key => $data) {
if ($data['id'] == $the_id_youre_lloking_for) {
// The item has been found => add the new points to the existing ones
$data['points'] += $the_number_of_points;
$found = true;
break; // no need to loop anymore, as we have found the item => exit the loop
}
}
if ($found === false) {
// The id you were looking for has not been found,
// which means the corresponding item is not already present in your array
// => Add a new item to the array
}
you can first store the array with index equal to the id.
for example :
$arr =Array ( [0] => Array
( [id] => 1
[name] => Jonah
[points] => 27 )
[1] => Array
( [id] => 2
[name] => Mark
[points] => 34 )
);
$new = array();
foreach($arr as $value){
$new[$value['id']] = $value;
}
//So now you can check the array $new for if the key exists already
if(array_key_exists(1, $new)){
$new[1]['points'] = 32;
}
Even though the question is answered, I wanted to post my answer. Might come handy to future viewers. You can create new array from this array with filter then from there you can check if value exist on that array or not. You can follow below code. Sample
$arr = array(
0 =>array(
"id"=> 1,
"name"=> "Bangladesh",
"action"=> "27"
),
1 =>array(
"id"=> 2,
"name"=> "Entertainment",
"action"=> "34"
)
);
$new = array();
foreach($arr as $value){
$new[$value['id']] = $value;
}
if(array_key_exists(1, $new)){
echo $new[1]['id'];
}
else {
echo "aaa";
}
//print_r($new);

PHP/MySQL: Recreate multidimensional array from existing array

I've got an multi-array (currently with objects) that I want to reorder based on a specific key/value.
Array
(
[0] => stdClass Object
(
[task_id] => 1
[task_title] => Title
[users_username] => John
)
[1] => stdClass Object
(
[task_id] => 2
[task_title] => Title
[users_username] => John
)
[2] => stdClass Object
(
[task_id] => 3
[task_title] => Title
[users_username] => Mike
)
)
I'd like to reorder it to get multi-arrays by user_name, so I can cycle through the task by username.
Array
(
[John] => Array
(
[0] => Array
(
[task_id] => 1
[title] => Title
)
[1] => Array
(
[task_id] => 2
[title] => Title
)
)
[Mike] => Array
(
[0] => Array
(
[task_id] => 3
[title] => Title
)
)
)
Is it possible to recreate my array to an array like that above?
Updated version of the code
<?php
$it0 = (object) array('task_id' => 1,'task_title' => 'Title','users_username' => 'John');
$it1 = (object) array('task_id' => 2,'task_title' => 'Title','users_username' => 'John');
$it2 = (object) array('task_id' => 3,'task_title' => 'Title','users_username' => 'Mike');
$array = array($it0,$it1,$it2);
$return = array();
foreach($array as $id => $value){
$return[$value->users_username][] = array('task_id' => $value->task_id,'title' => $value->task_title);
}
var_dump($return);
Yes, it is possible.
You'll have to loop through your current array and create a new array to do it.
example:
$new_array = array();
foreach ($array as $row)
{
$new_row = array(
'task_id' => $row->task_id,
'title' => $row->task_title,
);
$name = $row->users_username;
if (isset($new_array[$name]))
{
$new_array[$name][] = $new_row;
}
else
{
$new_array[$name] = array($new_row);
}
}
Now $new_array contains the new array exactly like the one you're asking for.
Then you can sort it with
ksort($new_array);
There may be another way to do this, with some built-in function, but sometimes I'd rather just do it myself, and know how it is working, without having to look up the documentation.
The approach:
Iterate through all of the first array, looking at [users_username] and putting them into a new array.
Code:
$dst_array = array();
foreach ($src_array as $val)
{
$user = $val->users_username;
// TODO: This check may be unnecessary. Have to test to find out.
// If this username doesn't already have an array in the destination...
if (!array_key_exists($user, $dst_array))
$dst_array[$user] = array(); // Create a new array for that username
// Now add a new task_id and title entry in that username's array
$dst_array[$user][] = array(
'task_id' => $val->task_id
'title' => $val->title
);
}
Just something like this (maybe not 100% PHP code):
foreach ( $obj : $oldArray ) {
$newTask['task_id'] = $obj->task_id;
$newTask['title'] = $obj->title;
$newArray[$oldName][] = $newTask;
}
If you want to order it; you can just call a order function afterwards.

Categories