I've this type of array in PHP:
Array(
[100] => Array(
[1] => Array (
[AVA_Date] => 2019-04-18
[ROO_Id] => 100
[RAT_Id] => 9
)
[2] => Array (
[AVA_Date] => 2019-04-20
[ROO_Id] => 100
[RAT_Id] => 10
)
[4] => Array (
[AVA_Date] => 2019-04-21
[ROO_Id] => 100
[RAT_Id] => 10
)
[7] => Array (
[AVA_Date] => 2019-04-22
[ROO_Id] => 100
[RAT_Id] => 9
)
)
)
I would like to merge items on ROO_Id and RAT_Id.
Then, for the AVA_Date, I need to list them under a new array in the current array.
So, the desired output is:
Array(
[100] => Array(
[0] => Array (
[AVA_Date] => Array (
[0] => 2019-04-18
[1] => 2019-04-22
)
[ROO_Id] => 100
[RAT_Id] => 9
)
[1] => Array (
[AVA_Date] => Array (
[0] => 2019-04-20
[1] => 2019-04-21
)
[ROO_Id] => 100
[RAT_Id] => 10
)
)
)
Here what I have tried:
$newArrOtherRooms = array_reduce($newArr, function($acc, $val) {
$room = array_search($val['ROO_Id'], array_column($acc, 'ROO_Id'));
$rate = array_search($val['RAT_Id'], array_column($acc, 'RAT_Id'));
if($rate == $room && $room > -1) {
array_push($acc[$room]['AVA_Date'], $val['AVA_Date']);
}
else {
$new_arr = $val;
$new_arr['AVA_Date'] = [$val['AVA_Date']];
array_push($acc, $new_arr);
}
return $acc;
},[]);
But it doesn't work like I want.
There are a couple of issues with your code. Firstly, you need to wrap the array_reduce with a foreach over the outer level of $newArr. Secondly, your call to array_search doesn't consider the fact that a ROO_Id or RAT_Id value might exist more than once in the array, as it only returns the first key at which it finds the value. To work around this, you can use array_keys to get an array of key values for each ROO_Id and RAT_Id value, and then take the intersection of those two arrays using array_intersect to see if both are present in the same element. If so, you update that element, otherwise you create a new one:
foreach ($newArr as $key => $array) {
$newArrOtherRooms[$key] = array_reduce($array, function($acc, $val) {
$room = array_keys(array_column($acc, 'ROO_Id'), $val['ROO_Id']);
$rate = array_keys(array_column($acc, 'RAT_Id'), $val['RAT_Id']);
$common = array_intersect($room, $rate);
if(!empty($common)) {
array_push($acc[current($common)]['AVA_Date'], $val['AVA_Date']);
}
else {
$new_arr = $val;
$new_arr['AVA_Date'] = [$val['AVA_Date']];
array_push($acc, $new_arr);
}
return $acc;
},[]);
}
print_r($newArrOtherRooms);
Output:
Array(
[100] => Array(
[0] => Array (
[AVA_Date] => Array (
[0] => 2019-04-18
[1] => 2019-04-22
)
[ROO_Id] => 100
[RAT_Id] => 9
)
[1] => Array (
[AVA_Date] => Array (
[0] => 2019-04-20
[1] => 2019-04-21
)
[ROO_Id] => 100
[RAT_Id] => 10
)
)
)
Demo on 3v4l.org
There is absolutely no reason to be making all of those iterated function calls.
Use a nested loop to iterate the subset of data for each room, group on the room "rate id", and push all "available date" values into a subarray in the respective group. When the subset of data is fully iterated, push its grouped data into the result array.
Code: (Demo)
$result = [];
foreach ($newArr as $rooId => $rows) {
$groups = [];
foreach ($rows as $row) {
if (!isset($groups[$row['RAT_Id']])) {
$row['AVA_Date'] = (array) $row['AVA_Date'];
$groups[$row['RAT_Id']] = $row;
} else {
$groups[$row['RAT_Id']]['AVA_Date'][] = $row['AVA_Date'];
}
}
$result[$rooId] = array_values($groups);
}
var_export($result);
Output:
array (
100 =>
array (
0 =>
array (
'AVA_Date' =>
array (
0 => '2019-04-18',
1 => '2019-04-22',
),
'ROO_Id' => 100,
'RAT_Id' => 9,
),
1 =>
array (
'AVA_Date' =>
array (
0 => '2019-04-20',
1 => '2019-04-21',
),
'ROO_Id' => 100,
'RAT_Id' => 10,
),
),
)
Related
I have an array something like below. I want to merge the nested array and display the totals. Here ID = 60.I want to merge this [0] and [1] depending in the ID value i.e., 60.
Array(
[0] => Array
(
[ID] => 60
[TOTAL] => 500
)
[1] => Array
(
[ID] => 60
[TOTAL] => 600
)
[2] => Array
(
[ID] => 61
[TOTAL] => 600
)
)
I tried with two for loops
foreach($result as $key=>$value){
foreach($result as $key1 => $value1){
// Do stuffs here
}
}
I want the output as
Array(
[0] => Array(
[ID] =>60
[TOTAL] => 1100
)
[1] =>Array(
[ID] =>61
[TOTAL] => 600
)
)
<?php
$result = Array(
Array
(
'ID' => 60,
'TOTAL' => 500
),
Array
(
'ID' => 60,
'TOTAL' => 600
),
Array
(
'ID' => 61,
'TOTAL' => 600
)
);
$set = [];
foreach($result as $data){
if(!isset($set[$data['ID']])) $set[$data['ID']] = 0;
$set[$data['ID']] += $data['TOTAL'];
}
$result_set = [];
foreach($set as $id => $total){
$result_set[] = [
'ID' => $id,
'TOTAL' => $total
];
}
print_r($result_set);
Demo: https://3v4l.org/NMmHC
We store IDs as keys in our $set array and keep adding the total to it whenever we come across the same key in the foreach loop.
In the end, we collect the results in a new array with ID and it's respective total.
My suggestion is to use array_reduce() which iteratively reduce the array to a single value using a callback function.
$arr = [['ID' => 60,'TOTAL' => 500],['ID' => 60,'TOTAL' => 600],['ID' => 61,'TOTAL' => 600]];
$arr = array_reduce($arr, function($acc, $new) {
if (!isset($acc[$new['ID']])) {
$acc[$new['ID']] = $new;
return $acc;
}
$acc[$new['ID']]['TOTAL'] += $new['TOTAL'];
return $acc;
}, []);
echo '<pre>', print_r(array_values($arr));
Working demo.
Solution 1
$arrayvariable=Array(
[0] => Array
(
[ID] => 60
[TOTAL] => 500
)
[1] => Array
(
[ID] => 60
[TOTAL] => 600
)
[2] => Array
(
[ID] => 61
[TOTAL] => 600
)
)
$output = array_reduce($arrayvariable, function (array $compare, array $item) {
$intrestkey = $item ['ID'];
if (array_key_exists($intrestkey, $compare)) {
$compare [$intrestkey] ['TOTAL'] += $item ['TOTAL'];
} else {
$compare [$intrestkey] = $item;
}
return $compare;
}, array());
$incremetedmerged_array = array_values($output);
print_r($incremetedmerged_array); //Produces
Array(
[0] => Array(
[ID] =>60
[TOTAL] => 1100
)
[1] =>Array(
[ID] =>61
[TOTAL] => 600
)
)
I have on array of data in below.
Array
(
[0] => Array
(
[0] => Array
(
[rating] => 4
[review] => nice
)
[1] => Array
(
[rating] => 2
[review] => good
)
)
)
We customize above array and need to my custom array .
Need out put like below array. array always need 5 to 1 key because i am using this array for rating & review functionality.
Array
(
[0] => Array
(
[5] => Array
(
[rating] => 0
[review] => ""
)
[4] => Array
(
[rating] => 4
[review] => nice
)
[3] => Array
(
[rating] => 0
[review] => ""
)
[2] => Array
(
[rating] => 2
[review] => "good"
)
[1] => Array
(
[rating] => 0
[review] => ""
)
)
)
I managed to self-solve. Please find below solution as per output.
$arr1 = array(array("rating"=>4,"review"=>"nice"),array("rating"=>2,"review"=>"good"));
$final =a rray();
for ($i=5; $i>=1; $i--) {
foreach ($arr1 as $key =>$val) {
if ($val['rating']==$i) {
$final[$i] = array("rating"=>$val['rating'],"review"=>$val['review']);
break;
} else {
$final[$i] = array("rating"=>0,"review"=>"");
}
}
}
print_r($final);
Iterate each top level array (if you don't have multiple top level arrays, then you should consider restructuring your array structure to be more concise)
call array_column() on the level2 array so that the rating values are assigned as keys for their respective subarray.
Iterate in descending order from 5 to 1 while conditionally saving data to the output array.
Code: (Demo)
$input = [
[
['rating' => 4, 'review' => 'nice'],
['rating' => 2, 'review' => 'good']
]
];
foreach ($input as $x => $level2) {
$keyed = array_column($level2, null, 'rating'); // setup more efficient lookup
for($i = 5 ; $i > 0 ; --$i) {
$result[$x][$i] = isset($keyed[$i]) ? $keyed[$i] : ['rating' => 0, 'review' => ''];
}
}
var_export($result);
// output is as desired
I have an array like below: all the values I am getting one array only, but I don't want this way. This is the best way to do so, in php or jQuery both languages are ok for me
Array
(
[0] => Array
(
[val] => facebook
)
[1] => Array
(
[val] => snapchat
)
[2] => Array
(
[val] => instagram
)
[3] => Array
(
[expenses] => 986532
)
[4] => Array
(
[expenses] => 45456
)
[5] => Array
(
[expenses] => 56230
)
[6] => Array
(
[social_id] => 15
)
[7] => Array
(
[social_id] => 16
)
[8] => Array
(
[social_id] => 17
)
)
and I want to output like this..
$result = array(
array(
"val" => "Facebook",
"expenses" => "84512",
"social_id" => 1
),
array(
"val" => "Instagram",
"expenses" => "123",
"social_id" => 2
)
);
but this should be dynamic, the length of the above array can be varies
You can merge the arrays to one and use array_column to get all vals or expenses in a separate array.
Then foreach one array and build the new array with the key.
//$a = your array
// Grab each column separate
$val = array_column($a, "val");
$expenses= array_column($a, "expenses");
$social_id = array_column($a, "social_id");
Foreach($val as $key => $v){
$arr[] = [$v, $expenses[$key], $social_id[$key]];
}
Var_dump($arr);
https://3v4l.org/nVtDf
Edit updated with the 'latest' version of the array. My code works just fine with this array to without any changes.
to get that array style you can do it by hand for each array
function test(array ...$arr)
{
$result = array();
foreach ($arr as $key => $pair) {
foreach ($pair as $item => $value) {
$result[$item] = $value;
}
}
return $result;
}
$arr1 = test( ['facebook' => 1], ['expenses' => 100]);
print_r($arr1);
/* Array (
[facebook] => 1,
[expenses] => 100
)
*/
$arr2 = test( $arr1, ['more info' => 'info'] );
print_r($arr2);
/* Array (
[facebook] => 1,
[expenses] => 100,
[more info] => info
)
*/
you can pass it any number of
['Key' => 'Pair']
array('Key' => 'Pair')
or even a previous made array and it will add them up into 1 big array and return it
Input post :
$_POST['dateSlot']
$_POST['timeStart']
$_POST['timeEnd']
$_POST['quota']
These input post will resulting the below array.
Array
(
[dateSlot] => Array
(
[0] => 2018-04-05
[1] => 2018-04-05
[2] => 2018-04-05
)
[timeStart] => Array
(
[0] => 11:06 AM
[1] => 10:06 AM
[2] => 9:06 AM
)
[timeEnd] => Array
(
[0] => 11:06 AM
[1] => 9:06 AM
[2] => 7:06 AM
)
[quota] => Array
(
[0] => 12
[1] => 10
[2] => 10
)
)
I'm trying to foreach them to match the index key and form another array with this idea. Not so sure if can get the value I want :
foreach ($_POST['dateSlot'] as $k => $val) {
foreach ($_POST['timeStart'] as $k2 => $val2) {
foreach ($_POST['timeEnd'] as $k3 => $val3) {
foreach ($_POST['quota'] as $k4 => $val4) {
if($k == $k2 && $k == $k3 && $k == $k4){
$timeslots[$k]['date_slot'] = $val;
$timeslots[$k]['time_start'] = $val2;
$timeslots[$k]['time_end'] = $val3;
$timeslots[$k]['event_quota'] = $val4;
}
}
}
}
}
By that foreach, I'm getting the error Illegal string offset for date_slot, time_start, time_end, and event_quota
Based on the rows in the array, my goal is to re-form the array so that they all will be combined together to form 3 rows.
Example :
Array
(
[0] => Array
(
[date_slot] => 2018-04-05
[time_start] => 11:06 AM
[time_end] => 11:06 AM
[event_quota] => 12
)
[1] => Array
(
[date_slot] => 2018-04-05
[time_start] => 10:06 AM
[time_end] => 9:06 AM
[event_quota] => 10
)
[2] => Array
(
[date_slot] => 2018-04-05
[time_start] => 9:06 AM
[time_end] => 7:06 AM
[event_quota] => 10
)
)
Another approach to grouping this kind of data without needing to know the key names in advance.
This works by using the first row's data current( $data ) as the main iterator, then builds an array by combining the outer keys array_keys( $data ) and the inner column value array_column( $data, $column ) with array_combine() which combines two arrays of keys and an array of value to make each row's final array structure keyed by column name.
This is absolutely reliant on each multidimensional array having the same count of elements. As such this is not suitable for forms with checkbox inputs in them. At which point I would suggest using name="row[0][ColumnName]" as your name attribute and negating the need for this array processing.
http://php.net/manual/en/function.array-column.php
http://php.net/manual/en/function.array-combine.php
http://php.net/manual/en/function.array-keys.php
$data = array(
'Column-1'=>array('Row-1a','Row-2a','Row-3a'),
'Column-2'=>array('Row-1b','Row-2b','Row-3b'),
'Column-3'=>array('Row-1c','Row-2c','Row-3c')
);
$array = array();
foreach( array_keys( current( $data ) ) as $column )
{
$array[] = array_combine( array_keys( $data ), array_column( $data, $column ) );
}
print_r( $array );
Produces
Array
(
[0] => Array
(
[Column-1] => Row-1a
[Column-2] => Row-1b
[Column-3] => Row-1c
)
[1] => Array
(
[Column-1] => Row-2a
[Column-2] => Row-2b
[Column-3] => Row-2c
)
[2] => Array
(
[Column-1] => Row-3a
[Column-2] => Row-3b
[Column-3] => Row-3c
)
)
If you know that the element keys in all 4 of those post variables will always correlate to one timeslot element, then I think this will work for you:
foreach ($_POST['dateSlot'] as $key => $value) {
$timeslots[$key] = [
'date_slot' => $_POST['dateSlot'][$key],
'time_start' => $_POST['timeStart'][$key],
'time_end' => $_POST['timeEnd'][$key],
'event_quota' => $_POST['quota'][$key],
];
}
print_r($timeslots);
$dateSlot = $_POST['dateSlot']
$timeStart = $_POST['timeStart']
$timeEnd = $_POST['timeEnd']
$quota = $_POST['quota']
$all = array();
foreach($dateSlot as $key => $date) {
$all[] = array(
"data_slot" => $dateSlot[$key],
"time_start" => $timeStart[$key],
"time_end" => $timeEnd[$key],
"quota" => $quota[$key]
)
}
Input
$array = array(
'dateSlot' => array('2018-04-05','2018-04-05','2018-04-05'),
'timeStart' => array('11:06 AM','10:06 AM','9:06 AM'),
'timeEnd' => array('11:06 AM','9:06 AM','7:06 AM'),
'quota' => array(12,10,10)
);
Solution
$new = array();
for($i=0;$i<count($array['dateSlot']);$i++){
$new[] = array(
'dateSlot' => $array['dateSlot'][$i],
'timeStart' => $array['timeStart'][$i],
'timeEnd' => $array['timeEnd'][$i],
'event_quota' => $array['quota'][$i],
);
}
echo "<pre>";print_r($new);
Output
Array
(
[0] => Array
(
[dateSlot] => 2018-04-05
[timeStart] => 11:06 AM
[timeEnd] => 11:06 AM
[event_quota] => 12
)
[1] => Array
(
[dateSlot] => 2018-04-05
[timeStart] => 10:06 AM
[timeEnd] => 9:06 AM
[event_quota] => 10
)
[2] => Array
(
[dateSlot] => 2018-04-05
[timeStart] => 9:06 AM
[timeEnd] => 7:06 AM
[event_quota] => 10
)
)
I have two arrays. I have combined both the arrays to output the total
1st array =
$farray = Array (
[0] => Array (
[1] => Array (
[ED] => 15
[EN] => 14
)
)
[1] => Array (
[2] => Array (
[ED] => 5
[EN] => 10
)
)
)
2nd Array =
$tarray = Array (
[0] => Array (
[1] => Array (
[ED] => 45
[EN] => 50
)
)
[1] => Array (
[2] => Array (
[ED] => 38
[EN] => 40
)
)
)
The combination of the above two arrays:
$all = Array (
[0] => Array (
[1] => Array (
[ED] => 60
[EN] => 64
)
)
[1] => Array (
[2] => Array (
[ED] => 43
[EN] => 50
)
)
)
Now I want to use the first array and the second array for inserting condition into the following codes:
$fscore = array_reduce(
$farray,
function($farray, $item) {
$id = key($item);
$scores = $item[$id];
$farray[$id] = array(
"score" => array_sum($scores),
"farray"=> min($scores)>=7
);
return $farray;
},
array()
);
The above attempt works and output the following (print_r($fscore)):
Array (
[1] => Array (
[score] => 124
[farray] => 1
)
[2] => Array (
[score] => 93
[farray] => 0
)
)
But I want to put more conditions to it and combine with the $tarray like below:
$all= array_reduce(
$all,
function($all, $item) {
$id = key($item);
$scores = $item[$id];
$all[$id] = array(
"score" => array_sum($scores),
"farray"=> min($scores)>=7
//if tarray key==ED 23 else 26 for minimum `$scores`
"tarray"=> min($scores)>='ED'? 23:26//ternary operator
);
return $all;
},
array()
);
I don't know how to insert the $tarray. As stated earlier, without the $tarray, it works.
My attempts failed and does not output expected result. In this question I only used ED and EN (score keys) to save more space. The minmum score expected for $farray is greater than or equal to 7 whereas the minimum score expected for $tarray is 23/26. If the score key is ED in $tarray, the minimum score is greater than or equal to 23, else it must be 26. Depending on those conditions, I want to return true or false value. Please help. Below is my attempt:
$farray = array(
array (
1=> array(
"ED"=>15,
"EN"=>14
)
),
array(
2=>array(
"ED"=>5,
"EN"=>10
)
)
);
$tarray = array (
array (
1 => array (
"ED" => 45,
"EN" => 50
)
),
array (
2 => array (
"ED" => 38,
"EN" => 40
)
)
);
$combine = array (
array (
1 => array (
"ED" => 60,
"EN" => 64
)
),
array (
2 => array (
"ED" => 43 ,
"EN" => 50
)
)
);
function filtertArray($value){
foreach($value as $key =>$val){
foreach($val as $k=>$v){
foreach($v as $t=>$m){
if($t=='ED'){
return $m>=23;
}else{
return $m>=26;
}
}
}
}
}
function filterfArray($value){
foreach($value as $key =>$val){
foreach($val as $k=>$v){
foreach($v as $t=>$m){
return $m>=7;
}
}
}
}
$all = array_reduce(
$combine,
function($combine, $item) use ($farray, $tarray) {
$id = key($item);
$scores = $item[$id];
$combine[$id] = array(
"score" => array_sum($scores),
"farray"=> array_filter($farray,"filterfArray"),
"tarray"=> array_filter($tarray,"filtertArray")
);
return $combine;
},
array()
);
echo "<pre>";
print_r($all);
echo "</pre>";
This outputs:
E_WARNING : type 2 -- Invalid argument supplied for foreach()
The expected output from this code is:
Array (
[1] => Array (
[score] => 124
[farray] => true//1
[tarray] => true//1
)
[2] => Array (
[score] => 93
[farray] => false//0
[tarray] => true//1
)
)
I don't think I'd bother trying to spice this answer up with an array_reduce() call. It is more important to comprehensibly deliver the correct comparisons and result. You are certainly welcome to convert my series of foreach loops to array functions.
My latest edit added more sample score data with the newly advised keys. The adjustment to $fscore's tarray comparison is that now the lowest non-ED score is compared against 26.
Code: (Demo)
$farray=[[1=>['ED'=>15,'EN'=>14,'MT'=>16,'MZ'=>20]],[2=>['ED'=>5,'EN'=>10,'MT'=>36,'MZ'=>30]]];
$tarray=[[1=>['ED'=>45,'EN'=>50,'MT'=>28,'MZ'=>27]],[2=>['ED'=>38,'EN'=>40,'MT'=>56,'MZ'=>60]]];
// generate $all
foreach($farray as $i=>$a){
foreach($a as $n=>$scores){
foreach($scores as $k=>$v){
$all[$i][$n][$k]=$v+$tarray[$i][$n][$k]; // sum the relative scores
}
}
}
var_export($all);
echo "\n\n";
// generate $fscores
$sub23_keys=array_flip(['ED']); // store list of keys that have lower score minimum
foreach($all as $i=>$a){
foreach($a as $n=>$scores){
$fscores[$n]['score']=array_sum($scores);
$fscores[$n]['farray']=min($farray[$i][$n])>=7; // check that both ED and EN scores are >=7
$fscores[$n]['tarray']=min(array_intersect_key($tarray[$i][$n],$sub23_keys)) && min(array_diff_key($tarray[$i][$n],$sub23_keys))>=26;
}
}
var_export($fscores);
Output:
// $all=
array (
0 =>
array (
1 =>
array (
'ED' => 60,
'EN' => 64,
'MT' => 44,
'MZ' => 47,
),
),
1 =>
array (
2 =>
array (
'ED' => 43,
'EN' => 50,
'MT' => 92,
'MZ' => 90,
),
),
)
//$fscores=
array (
1 =>
array (
'score' => 215,
'farray' => true,
'tarray' => true,
),
2 =>
array (
'score' => 275,
'farray' => false,
'tarray' => true,
),
)