How to Group PHP Array Based On Year with Nested Array - php

My Current PHP Array Outputs like this:
Array
(
[0] => Array
(
[year] => 2015
[month] => November
)
[1] => Array
(
[year] => 2015
[month] => October
)
[2] => Array
(
[year] => 2015
[month] => September
)
[3] => Array
(
[year] => 2015
[month] => August
)
[4] => Array
(
[year] => 2015
[month] => July
)
[5] => Array
(
[year] => 2015
[month] => June
)
[6] => Array
(
[year] => 2015
[month] => May
)
[7] => Array
(
[year] => 2015
[month] => April
)
[8] => Array
(
[year] => 2015
[month] => March
)
[9] => Array
(
[year] => 2015
[month] => February
)
[10] => Array
(
[year] => 2015
[month] => January
)
[11] => Array
(
[year] => 2014
[month] => December
)
[12] => Array
(
[year] => 2014
[month] => November
)
[13] => Array
(
[year] => 2014
[month] => October
)
[14] => Array
(
[year] => 2014
[month] => September
)
[15] => Array
(
[year] => 2014
[month] => August
)
[16] => Array
(
[year] => 2014
[month] => July
)
)
I want to sort the above Array and group them based on the Year. The Array I want to convert the above is to get like this:
Array (
[0] => Array
(
[yearGroup] => “2015”
[dates] => Array
(
[0] => Array
(
[year] => 2015
[month] => November
)
[1] => Array
(
[year] => 2015
[month] => October
)
…etc..etc…
)
)
[1] => Array
(
[yearGroup] => 2014
[dates] => Array
(
[0] => Array
(
[year] => 2014
[month] => December
)
[1] => Array
(
[year] => 2014
[month] => November
)
…etc..etc…
)
)
)
This is the code I have tried so far:
$calendar = // ..... The Array Above .....;
$sidebarCalendar = array();
$currentYear = '';
$i = 0;
foreach ($calendar as $date) {
if ($currentYear != $date['year']) {
$currentYear = $date['year'];
$i++;
$tempYearDates = array();
$j = 0;
$tempYearDates[$j] = array(
'year' => $date['year'],
'month' => $date['month']
);
$j++;
// Add to Array
$sidebarCalendar[$i] = array (
'yearGroup' => $date['year'],
'dates' => $tempYearDates
);
}
else {
$tempYearDates = array(
'year' => $date['year'],
'month' => $date['month']
);
// Locate the Array Tree
$currentParent = $sidebarCalendar[$i];
$currentArray = $currentParent['dates'];
$currentArray[$j] = $tempYearDates;
$j++;
}
}
But the above outputs incomplete array like this:
Array
(
[1] => Array
(
[yearGroup] => 2015
[dates] => Array
(
[0] => Array
(
[year] => 2015
[month] => November
)
)
)
[2] => Array
(
[yearGroup] => 2014
[dates] => Array
(
[0] => Array
(
[year] => 2014
[month] => December
)
)
)
)
Can someone point out what I have got wrong here please? If there is a better way to do the same instead of the above method, please do guide me there please…

You could use some of the builtin PHP's array functions to solve this issue. First thing you want to do is get all the unique years in that array, so you could do:
$years = array_unique(array_map(function($item) { return $item['year']; }, $calendar));
Here, I've used array_map to get an array containing only the year property for each item, and fed it to the array_unique function to get only unique values.
Next thing you could do is iterate through all the years, and populate another array, something like this:
$grouped = [];
foreach($years as $year) {
$grouped[$year] = array_filter($calendar, function($item) use ($year) { return $item['year'] === $year; });
}
This way you'll get a key for each year in the grouped variable, and each key will contain a subarray composed only of the elements of calendar satisfying the array_filter condition.
I'm sure there are better / more optimized ways of doing this (maybe using array_walk or array_reduce?) and I encourage you to find those! Still, remember that there are many array functions builtin in PHP, read their documentation and learn when to use them, they'll be of great help!
Edit: I realize that the output of my solution is not exactly what you're expecting, but it's very easily adaptable. I myself prefer using keyed arrays (maps?) whenever possible in place of regular arrays with properties, but to each their own!
$grouped = [];
foreach($years as $year) {
$grouped[] = [
'yearGroup' => $year,
'dates' => array_filter($calendar, function($item) use ($year) { return $item['year'] === $year; })
];
}
Edit 2: Sometimes I forget how to PHP.

Related

Loop through an array and group prices by month, Morris chart

I want to group results by month, to be precise Sum of total prices for each month, but i don't understand how i can divide months, then Sum price for each month.
This is required for morris chart like this
$data2[] = array(
'y' => $month,
'a' => price,
'b' => ''
);
I was using before query to get this results and was a easy way to do it, but now with code is different story.
Any help with explanation of how each segment of code is work will be so nice, so i can avoid problems like this one in future.
I need something like this :
$month = [May, June];
$price = [Sum of all prices for May, Sum of all prices for June];
This is a code :
$monthsArray = array();
// get all dates in array
foreach ($array as $key) {
// convert dates to short format, month-year -> Jun-18
$monthsArray[] = date('M-y', strtotime($key['time']));
}
$months = array();
foreach ($monthsArray as $date) {
$mon = substr($date, 0, 6);
if (!in_array($mon, $months)) array_push($months, $mon);
}
foreach ($months as $m) {
// final array for chart
$data2[] = array('y'=>$m, 'a'=>'', 'b'=>'');
}
$morris = json_encode($data2);
This is array i have
Array
(
[0] => Array
(
[price] => -1835.25
[time] => 2018-05-29 16:53:38
)
[1] => Array
(
[price] => -1743.52
[time] => 2018-05-29 16:53:39
)
[2] => Array
(
[price] => -4445.55
[time] => 2018-05-31 13:21:04
)
[3] => Array
(
[price] => -34647.04
[time] => 2018-05-31 18:29:43
)
[4] => Array
(
[price] => 16888.41
[time] => 2018-06-01 15:05:24
)
[5] => Array
(
[price] => 14369.05
[time] => 2018-06-07 14:44:21
)
[6] => Array
(
[price] => -49579.69
[time] => 2018-06-11 09:14:42
)
[7] => Array
(
[price] => -33300.94
[time] => 2018-06-08 23:50:29
)
[8] => Array
(
[price] => 4413.21
[time] => 2018-06-12 07:15:52
)
[9] => Array
(
[price] => 2724.69
[time] => 2018-06-12 07:15:46
)
[10] => Array
(
[price] => 10224.03
[time] => 2018-06-08 14:00:13
)
[11] => Array
(
[price] => -797.92
[time] => 2018-06-08 13:54:08
)
[12] => Array
(
[price] => -25157.34
[time] => 2018-06-11 11:31:31
)
[13] => Array
(
[price] => 2701.6
[time] => 2018-06-11 14:32:08
)
[14] => Array
(
[price] => 2038.92
[time] => 2018-06-12 07:15:48
)
[15] => Array
(
[price] => -10541.58
[time] => 2018-06-15 10:35:58
)
)
EDIT:
I manage to group months as you can see in updated code and now i am getting only 2 results as i should be, now its just a issue with SUM of data for each month.
This is what i am getting in console
0: {y: "May-18", a: "", b: ""}
1: {y: "Jun-18", a: "", b: ""}

Search array of dates does not return result

Hello I am trying to search for an hour based on the current date with the following function:
$key = array_search($todayday, array_column($days, 'date', 'hours'));
Where $todayday is equal to today day which comes from the sever day date.
the Array $days is:
Array
(
[0] => Array
(
[date] => 01
[hours] => 0
)
[1] => Array
(
[date] => 02
[hours] => 8
)
[2] => Array
(
[date] => 03
[hours] => 16
)
[3] => Array
(
[date] => 04
[hours] => 24
)
[4] => Array
(
[date] => 05
[hours] => 32
)
[5] => Array
(
[date] => 06
[hours] => 40
)
[6] => Array
(
[date] => 07
[hours] => 40
)
... etc....
while $todaydate is equal to 1,2,3,4,5 it works. but for 6 and 7 does not return anything. Any help is welcome to resolve this issue. Thanks
I suspect that since date = 6 and 7 have the same value of hours this is why it does not return anything but the question is how to return it actually.
Your supposition is correct, you can not have duplicate keys. Use the key from the search and then access hours:
$key = array_search($todayday, array_column($days, 'date'));
$hours = $days[$key]['hours'];
Or shorter:
$hours = $days[array_search($todayday, array_column($days, 'date'))]['hours'];
In the case where the indexes are not 0 based and sequential, use array_values() to re-index:
$days = array_values($days);
$key = array_search($todayday, array_column($days, 'date'));
$hours = $days[$key]['hours'];

Combine intersecting keys and values in 2 arrays

I'm running through all of the array functions on php.net and unable to figure this out.
Essentially I want to take these two arrays:
Array
(
[0] => stdClass Object
(
[month] => October
[year] => 2015
[credit] => 1000.00
)
[1] => stdClass Object
(
[month] => September
[year] => 2015
[credit] => 200.00
)
)
Array
(
[0] => stdClass Object
(
[month] => October
[year] => 2015
[debit] => 2000.00
)
[1] => stdClass Object
(
[month] => August
[year] => 2015
[debit] => 50.00
)
)
...and have the output look like this:
Array
(
[0] => stdClass Object
(
[month] => October
[year] => 2015
[credit] => 1000.00
[debit] => 2000.00
)
[1] => stdClass Object
(
[month] => September
[year] => 2015
[credit] => 200.00
[debit] => 0
)
[2] => stdClass Object
(
[month] => August
[year] => 2015
[credit] => 0
[debit] => 50.00
)
)
I'm looked to merge "month" and "year" and combine the other keys, using a default value if the key doesn't exist. Any guidance?
Assuming $debits and $credits are the arrays shown in your question, I would approach it like this:
First loop over the credits, inserting them into the new "combined" array and adding a default value for debit as you go.
foreach ($credits as $credit) {
$credit->debit = 0.00; // provide a default value for debit
$combined[$credit->year . $credit->month] = $credit;
}
Then loop over the debits. Since there is the possibilities that entries will already be there from credits, there needs to be a check for this. This part should update existing values inserted from credits, or insert new values if there is no existing value.
foreach ($debits as $debit) {
if (isset($combined[$debit->year . $debit->month])) {
// update the debit if the entry already exists
$combined[$debit->year . $debit->month]->debit = $debit->debit;
} else {
// otherwise create a new entry with a default value for credit
$debit->credit = 0.00;
$combined[$debit->year . $debit->month] = $debit;
}
}
// If you need the results to be numerically indexed, you can use array_values
$numerically_indexed = array_values($combined);

Sort Multiarray in php [duplicate]

This question already has answers here:
How can I sort arrays and data in PHP?
(14 answers)
Closed 2 months ago.
I need some help about sorting a multiple array.
This is what I got:
Array (
[ALU0000001] =>
Array ( [0] => Array ( [period] => 2012 [codCurse] => S12-2030 [idPersona] => ALU0000001 [date] => 2012-04-02 [amount] => 238.00 [active] => X )
[1] => Array ( [period] => 2012 [codCurse] => S12-2030 [idPersona] => ALU0000001 [date] => 2012-05-02 [amount] => 238.00 [active] => X )
[2] => Array ( [period] => 2012 [codCurso] => S12-2030 [idPersona] => ALU0000001 [date] => 2012-06-02 [amount] => 238.00 [active] => X )
[3] => Array ( [period] => 2013 [codCurso] => S12-2030 [idPersona] => ALU0000001 [date] => 2013-01-02 [amount] => 238.00 [active] => X )
[ALU0000005] =>
Array ( [0] => Array ( [period] => 2013 [codCurse] => S13-2010 [idPersona] => ALU0000005 [date] => 2013-03-01 [amount] => 225.00 [active] => X )
[1] => Array ( [period] => 2013 [codCurse] => S13-2010 [idPersona] => ALU0000005 [date] => 2013-03-02 [amount] => 333.00 [active] => X )
[2] => Array ( [period] => 2013 [codCurse] => S13-2010 [idPersona] => ALU0000005 [date] => 2013-04-02 [amount] => 333.00 [active] => X )
I need to sort multiarray by period date to get something like this
Y M D
2012 2012-04-02 ALU00000001 .....
2012 2012-05-02 ALU00000005 .....
2012 2012-06-01 ALU00000001 .....
2013 2013-01-01 ALU00000001 .....
2013 2013-06-01 ALU00000001 .....
2013 2013-12-24 ALU00000005 .....
Thanks
As danp says you will need a custom sort function using PHP usort.
You execute this in Codeigniter using the syntax;
usort($data_array, array('controller', 'sort_function'));
function sort_function($a, $b)
{
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
Considering the main array keys don't do much (because they're already contained within the values by the date key) you can safely ignore them. So first you want to collect all the values into a single array to be able to sort later:
$allItems = array();
foreach ($outputArr as $arr) { // $outputArr should be the name of your array
$allItems = array_merge($allItems,array_values($arr));
}
Then you need to sort the array values by the date keys:
function sortByDate($a,$b) {
$d1 = strtotime($a['date']);
$d2 = strtotime($b['date']);
return $d1 == $d2 ? 0 : ($d1 > $d2 ? 1 : -1);
}
usort($allItems,'sortByDate');
// and there you go.
print_r($allItems);

Sorting by key in a multidimensional array with php [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Sorting multidimensional array in PHP
How can I sort by key in a multidimensional array?
For instance, below is the array I print from my db, where the latest comes first - December, November, October, etc and 2011, 2010, 2009, etc
Array
(
[0] => Array
(
[URL] => september 2011
[Title] => September 2011
[Date] => 8
[Month] => 9
[Year] => 2011
)
[1] => Array
(
[URL] => january 2011
[Title] => January 2011
[Date] => 1
[Month] => 2
[Year] => 2011
)
[2] => Array
(
[URL] => february 2011
[Title] => February 2011
[Date] => 4
[Month] => 1
[Year] => 2011
)
[3] => Array
(
[URL] => november 2011
[Title] => November 2011
[Date] => 23
[Month] => 11
[Year] => 2010
)
[4] => Array
(
[URL] => april 2011
[Title] => April 2011
[Date] => 23
[Month] => 4
[Year] => 2010
)
)
But I need it to be like this, October, November, December, etc and 2011, 2010, 2009, etc - note the months are sorted by the oldest comes first but the years are still sorted by the latest comes first.
So the array should be sorted like this,
Array
(
[2] => Array
(
[URL] => february 2011
[Title] => February 2011
[Date] => 4
[Month] => 1
[Year] => 2011
)
[1] => Array
(
[URL] => january 2011
[Title] => January 2011
[Date] => 1
[Month] => 2
[Year] => 2011
)
[0] => Array
(
[URL] => september 2011
[Title] => September 2011
[Date] => 8
[Month] => 9
[Year] => 2011
)
[4] => Array
(
[URL] => april 2010
[Title] => April 2010
[Date] => 23
[Month] => 4
[Year] => 2010
)
[3] => Array
(
[URL] => november 2010
[Title] => November 2010
[Date] => 23
[Month] => 11
[Year] => 2010
)
)
Is that possible?
Generic solution to sort arrays of arrays with multiple keys
Based on my answer to this question, here is a very generic solution that you can use in lots of situations.
Limitation: Requires PHP >= 5.3 to work, due to the presence of anonymous functions.
New and improved, now with descending sort support
function make_comparer() {
$criteriaNames = func_get_args();
$comparer = function($first, $second) use ($criteriaNames) {
// Do we have anything to compare?
while(!empty($criteriaNames)) {
// What will we compare now?
$criterion = array_shift($criteriaNames);
// Used to reverse the sort order by multiplying
// 1 = ascending, -1 = descending
$sortOrder = 1;
if (is_array($criterion)) {
$sortOrder = $criterion[1] == SORT_DESC ? -1 : 1;
$criterion = $criterion[0];
}
// Do the actual comparison
if ($first[$criterion] < $second[$criterion]) {
return -1 * $sortOrder;
}
else if ($first[$criterion] > $second[$criterion]) {
return 1 * $sortOrder;
}
}
// Nothing more to compare with, so $first == $second
return 0;
};
return $comparer;
}
How to use it
To sort by year ascending:
uasort($array, make_comparer('Year'));
To sort by year ascending, then by month ascending:
uasort($array, make_comparer('Year', 'Month'));
To sort by year descending, then by month ascending:
uasort($array, make_comparer(array('Year', SORT_DESC), 'Month'));
This last one is what you 're after.
Assuming that the data you would have provided in your question would have been actually correct (taking Year, Month, Date as base to create a sort on), you can first index the array by those values and the sort the main array. I'm just writing it, otherwise you might misread the output of the Demo, the URL/Titles do not correspond to the numerical values given, but it just works:
// create an index by date
foreach($data as $k=>$v)
{
$index[$k] = sprintf('%04d-%02d-%02d', $v['Year'], $v['Month'], $v['Date']);
}
// sort data based on the index
array_multisort($index, SORT_DESC, $data);
How about:
Data:
$arr = Array (
Array (
'URL' => 'september 2011',
'Title' => 'September 2011',
'Date' => 8,
'Month' => 9,
'Year' => 2011,
),
Array (
'URL' => 'january 2011',
'Title' => 'January 2011',
'Date' => 1,
'Month' => 2,
'Year' => 2011,
),
Array (
'URL' => 'february 2011',
'Title' => 'February 2011',
'Date' => 4,
'Month' => 1,
'Year' => 2011,
),
Array (
'URL' => 'november 2011',
'Title' => 'November 2011',
'Date' => 23,
'Month' => 11,
'Year' => 2010,
),
Array (
'URL' => 'april 2011',
'Title' => 'April 2011',
'Date' => 23,
'Month' => 4,
'Year' => 2010,
),
);
code:
function compare($a, $b) {
if ($a['Year'] == $b['Year']) {
return ($a['Month'] - $b['Month']);
} else {
return ($b['Year'] - $a['Year']);
}
}
usort($arr, 'compare');
print_r($arr);
output:
Array
(
[0] => Array
(
[URL] => february 2011
[Title] => February 2011
[Date] => 4
[Month] => 1
[Year] => 2011
)
[1] => Array
(
[URL] => january 2011
[Title] => January 2011
[Date] => 1
[Month] => 2
[Year] => 2011
)
[2] => Array
(
[URL] => september 2011
[Title] => September 2011
[Date] => 8
[Month] => 9
[Year] => 2011
)
[3] => Array
(
[URL] => april 2011
[Title] => April 2011
[Date] => 23
[Month] => 4
[Year] => 2010
)
[4] => Array
(
[URL] => november 2011
[Title] => November 2011
[Date] => 23
[Month] => 11
[Year] => 2010
)
)

Categories