PHP loop, date sorting challenge - php

I'm having trouble trying to figure out how to achieve this programming challenge in my Zend Framework application:
I need to create an array that looks like this:
$array = array(
0 => stdClass()->monthName
->monthResources = array()
1 => stdClass()->monthName
->monthResources = array()
);
This is the original array I have to work with:
$resources = array(
0 => Resource_Model()->date (instance of Zend_Date)
1 => Resource_Model()->date
2 => Resource_Model()->date
//etc...
);
The original array ($resources) is already sorted by date (descending) so I need to create an array where the resources are grouped by month. I only want the months that have resources, so if the resources skip a month, there shouldn't be a stdClass object for that month in the final array.
I also want this to process quickly, so any advice on optimizing the code (and still being readable) would be great. How can I achieve this?

My offering. No guarantees on its speed however it is O(n) and should in theory be faster than your method. This may not be true in any or all cases. However if you want something optimized you should have used a profiler to ensure that this is the function that is causing the speed problems rather than trying to make sections of code fast when they only account for .001% of the execution time. (In which case the maximum gain from optimizing the function would be .001%)
$resources = $this->fetchAll();
$sortedresources = array();
foreach ($resources as $resource) {
$monthName = $resource->getDate()->get(Zend_Date::MONTH_NAME);
if ( !isset($sortedresources[$monthName]) ){
//setup new data for this month name
$month = new stdClass();
$month->name = $monthName;
$month->monthResources = array();
$sortedresources[$monthName] = $month;
}
$sortedresources[$monthName]->monthResources[] = $resource;
}
//return the values of the array, disregarding the keys
//so turn array('feb' => 'obj') to array(0 => 'obj)
return array_values($sortedresources);

Maybe this helps (pseudo-code)
$finalArray = new array();
$tempStdClass = null;
foreach ($resObj in $resources)
{
if ($tempStdClass == null)
$tempStdClass = new StdClass($resObj->date);
if (tempStdClass->monthName != $resObj->date)
{
array_push($finalArray, $tempStdClass);
$tempStdClass = new StdClass($resObj->date);
}
array_push($tempStdClass->monthResources, $resObj);
}

Related

Multidimensional arrays in PHP - how to add values using foreach

I have a multidimensional array defined as follows
$SquadList = array('name', 'position', 'dob', 'nation', 'games', 'goals', 'assists');
I'm looping through several foreach loops and storing data from JSON
foreach ($season as $key => $squad){
$SquadList[0] = $squad['full_name'];
$SquadList[1] = $squad['position'];
$SquadList[2] = gmdate("d-m-y", $birthday);
$SquadList[3] = $squad['nationality'];
$SquadList[4] = $squad['appearances_overall'];
$SquadList[5] = $squad['goals_overall'];
$SquadList[6] = $squad['assists_overall']; }
foreach ($season1 as $key => $squad){
$SquadList[0] = $squad['full_name'];
$SquadList[1] = $squad['position'];
$SquadList[2] = gmdate("d-m-y", $birthday);
$SquadList[3] = $squad['nationality'];
$SquadList[4] = $squad['appearances_overall'];
$SquadList[5] = $squad['goals_overall'];
$SquadList[6] = $squad['assists_overall'];
The code is messy. The output is only 2 elements when it should be 30+
I've tried array_push as follows
array_push($SquadList['name'], $squad['full_name'];
i'm not sure if i get the question correctly, but i imagine you want it to be structured something like this:
$SquadList = []; // define it as an array
$ctr = 0; // define a counter that would be used in the two iterations
foreach ($season as $key => $squad){
$SquadList[$ctr][0] = $squad['full_name'];
$SquadList[$ctr][1] = $squad['position'];
$SquadList[$ctr][2] = gmdate("d-m-y", $birthday);
$SquadList[$ctr][3] = $squad['nationality'];
$SquadList[$ctr][4] = $squad['appearances_overall'];
$SquadList[$ctr][5] = $squad['goals_overall'];
$SquadList[$ctr][6] = $squad['assists_overall'];
$ctr++; // increase counter
}
foreach ($season1 as $key => $squad){
$SquadList[$ctr][0] = $squad['full_name'];
$SquadList[$ctr][1] = $squad['position'];
$SquadList[$ctr][2] = gmdate("d-m-y", $birthday);
$SquadList[$ctr][3] = $squad['nationality'];
$SquadList[$ctr][4] = $squad['appearances_overall'];
$SquadList[$ctr][5] = $squad['goals_overall'];
$SquadList[$ctr][6] = $squad['assists_overall'];
$ctr++; // increase counter
}
The reason you had two results is because you got the last squad for each season. This happened because each time a season iterated, it overwrote the previous squad.
To solve this problem, $SquadList must be an array. But you have to assign all its members at once, otherwise the array will increment every time you add a member.
Populating an array of arrays
foreach ($season as $key => $squad) {
$squadList[] = [
$squad['full_name'],
$squad['position'],
gmdate("d-m-y", $squad['birthday']),
$squad['nationality'],
$squad['appearances_overall'],
$squad['goals_overall'],
$squad['assists_overall']
];
}
Note a couple of changes I made:
I removed the capitalization on $squadList because convention has starting with a capital indicating an object, not a plain old variable
$birthday was undefined, so I made an educated guess
Cleaning up the code
You mentioned that “the code is messy”. That is a very healthy observation to make.
What you are noticing is the result of two things:
Your code is repeating itself (a violation of DRY - Don’t Repeat Yourself)
Need to follow convention of PSR-12
So let’s get rid of the code duplication
Refactoring
When you start repeating yourself, that’s a signal to pull things into a function
function buildSquad(array $season)
{
foreach ($season as $key => $squad) {
$squadList[] = [
$squad['full_name'],
$squad['position'],
gmdate("d-m-y", $squad['birthday']),
$squad['nationality'],
$squad['appearances_overall'],
$squad['goals_overall'],
$squad['assists_overall']
];
}
return $squadList;
}
$squadList = [];
// if you just want to lump them all together
$squadList[] = buildSquad($season);
$squadList[] = buildSquad($season2);
// etc

Why is variable not changing in a PHP array of objects?

I am trying to assemble an array of objects from a variety of sources in PHP (I'm new to the language). The problem is that I am not able to store the data within the $bandwidthData array in the foreach loop I am trying to write.
private function _getData($startDay, $totalDays)
{
$devices = ubntDevices::getDevices();
$data = [];
$bandwidthData = [];
$count = 0;
foreach ($devices as $device) {
$bandwidthData[$count]['device'] = $device;
$bandwidthData[$count]['bandwidth'] = new ubntModel($device->file);
$bandwidthData[$count]['bandwidth']->getMonthData();
$bandwidthData[$count]['tree'] = new graphTree($device->hostid);
$bandwidthData[$count]['graphid'] = ubntGraph::getGraphByHostId($device->hostid);
$bandwidthData[$count]['hostname'] = $device->host_name;
$count++;
}
return $bandwidthData;
}
If I return from within the foreach loop, I get the correct output (but obviously for only the first device). I have tested all of the other function sources, and they seem to be returning the right data. Any idea what I could be doing wrong? Thank you in advance.
Your PHP error log should indicate what's going wrong. XDebug is very highly recommended as well.
However, nowadays it is more common to use an associative array like this:
private function _getData($startDay, $totalDays)
{
$devices = ubntDevices::getDevices();
$bandwidthData = [];
foreach ($devices as $device) {
$ubntModel = new ubntModel($device->file);
$deviceData = array('device' => $device,
'ubntModel' => $ubntModel,
'bandwidth' => $ubntModel->getMonthData(),
'tree' => new graphTree($device->hostid),
'graphid' => ubntGraph::getGraphByHostId($device->hostid),
'hostname' => $device->host_name);
$bandwidthData[] = $deviceData;
}
return $bandwidthData;
}
Some things I'm seeing:
Is this variable in use?
$data = [];
Also, this assignment runs but is a discouraged approach because at this point $bandwidthData[$count] does not exist:1
$bandwidthData[$count]['device'] = $device;
That can be converted to:
$bandwidthData[$count] = [ 'device' => $device ];
Also, this just a getter returning nowhere. Isn't it?
$bandwidthData[$count]['bandwidth']->getMonthData();
Also to further learn PHP I can suggest such cleaner approach for that code snippet, just to improve readability:
private function _getData( $startDay, $totalDays ) {
$bandwidthData = [];
foreach ( ubntDevices::getDevices() as $device ) {
$bandwidthData[] = [
'device' => $device,
'bandwidth' => new ubntModel( $device->file ),
'tree' => new graphTree( $device->hostid ),
'graphid' => ubntGraph::getGraphByHostId( $device->hostid ),
'hostname' => $device->host_name,
];
}
return $bandwidthData;
}
Anyway you have to learn how to debug that simple small block of code just looking at your server logs, or with a lazy var_dump( $bandwidthData[ $count ] ) in your suspected line (do not fight about this debugging approach: it's super stupid, but dramatically simple and effective, and friendly for newcomers - if you have not the possibility to setup a debugger because maybe the server is not yours etc.) or setting up a debugger.
1 from https://www.php.net/manual/en/language.types.array
If $arr doesn't exist yet, it will be created, so this is also an alternative way to create an array. This practice is however discouraged because if $arr already contains some value (e.g. string from request variable) then this value will stay in the place and [] may actually stand for string access operator. It is always better to initialize a variable by a direct assignment

create file json with multi array from a external json file

I made a search in stackoverflow, really I found a lot of threads about multi arrays, but no one can help me, for that reason a new thread, maybe someone can help me find a solution for my problem.
What I want is create a Json file getting values from a external json file.
Example what I want:
{
"day":[[1522108800000,6305.5],[1522195200000,6440.7]],
"month":[[1522108800000,6305.5],[1522195200000,6440.7]]
}
I tried my code, but only can get values from 1 json file, and not from both json files.
Please see and let me know if you can help / suggest something.
// Array Min
$json_min = file_get_contents("https://min-api.cryptocompare.com/data/histominute?fsym=BTC&tsym=EUR&limit=5&e=kraken");
// Array Day
$json_day = file_get_contents("https://min-api.cryptocompare.com/data/histoday?fsym=BTC&tsym=EUR&limit=5&e=kraken");
$array_min = json_decode($json_min, true);
$array_day = json_decode($json_day, true);
$array = array (
'day' => array (),
'month' => array (),
);
foreach($array_min['Data'] as $key)
{
$close_min = $key['close'];
$time_min = $key['time'];
$time_min = $time_min *1000;
$close_day = $key2['close'];
$time_day = $key2['time'];
$time_day = $time_day *1000;
$array['day'][] = [$time_min, $close_min];
$array['month'][] = [$time_day, $close_day];
}
$json_data = json_encode($array);
file_put_contents( 'json/history.json', $json_data);
Your mistakes were primarily: $array['Data'] does not exist, so the foreach will never run, and also you did not have any $key2 defined to read from the second array. You need to loop over each input array separately.
The code below will do it quite neatly.
It's possible to do it more verbosely with two totally independent loops (one for each input), but: since you wish to perform the same operations on both inputs, it's possible to do it in less code by placing both input arrays into a wrapper array, and giving it the entries keys which match the keys in the output array:
// Array Min
$json_min = file_get_contents("https://min-api.cryptocompare.com/data/histominute?fsym=BTC&tsym=EUR&limit=5&e=kraken");
// Array Day
$json_day = file_get_contents("https://min-api.cryptocompare.com/data/histoday?fsym=BTC&tsym=EUR&limit=5&e=kraken");
//place both inputs into an array labelled "day" and "month", ready for processing
$input = array("day" => json_decode($json_min, true), "month" => json_decode($json_day, true));
$output = array (
"day" => array(),
"month" => array(),
);
//loop through each entry in the input array
foreach ($input as $key => $data)
{
//loop through the actual data and process it
foreach($data['Data'] as $datakey => $value)
{
$close = $value['close'];
$time = $value['time'] * 1000;
//output the data to an array in "output" with the same key as the input array we're currently processing
$output[$key][] = [$time, $close];
}
}
$json_data = json_encode($output);
file_put_contents( 'json/history.json', $json_data);
See here: https://eval.in/1027493 for a working demo.

Can't push all array items into a second array PHP

So I have an array ($items) which has about 900 items in it. What I'm trying to do is, for the items that are read ($key["status"] == 1) which is about 300 items -> push those into a second array ($lifeSpanArray) with two attributes (added_date and read_date).
For some reason, when I try to push items into the lifespan array, I only have one item. Like I said, there are around 300 items that are status read - and I can dump those out, so I believe I am making a mistake with building my lifeSpanArray and pushing into it.
Any help much appreciated!
$items = $pocket->retrieve($params, $accessToken);
$numberArticles = count($items["list"]);
$hasRead = 0;
$hasNotRead = 0;
$readDatesArray = array();
$lifeSpanArray = array();
foreach ($items['list'] as $key) {
if ($key["status"] == 1) {
$hasRead++;
$timeAdded = date('m/d/Y', $key["time_added"]);
$dateRead = date('m/d/Y', $key["time_read"]);
// Where the problem is - only one item added
$lifeSpanArray['timeAdded'] = $timeAdded;
$lifeSpanArray['timeRead'] = $dateRead;
//Push into the read dates array
array_push($readDatesArray, $dateRead);
}
else {
$hasNotRead++;
}
}
var_dump($lifeSpanArray);
As you are overwriting your $lifeSpanArray array on each iteration you're must be getting only last entry so what you need is a two-dimension array,
Change this,
//Push into lifespan array
$lifeSpanArray['timeAdded'] = $timeAdded;
$lifeSpanArray['timeRead'] = $dateRead;
to,
$lifeSpanArray[] = array('timeAdded' => $timeAdded,'timeRead' => $dateRead);
$lifeSpanArray['timeAdded'] = $timeAdded;
$lifeSpanArray['timeRead'] = $dateRead;
For the above code, you are actually assigning a scalar value to $lifeSpanArray['timeAdded'] and $lifeSpanArray['timeRead'].
To treat them as array and push values to them, you should first initialize timeAdded and timeRead as arrays first:
$lifeSpanArray = array(
'timeAdded' => array(),
'timeRead' => array()
);
And pushing values to them within the foreach loop:
$lifeSpanArray['timeAdded'][] = $timeAdded;
$lifeSpanArray['timeRead'][] = $dateRead;

Add array to itself in foreach without duplicating?

public function GetOpsPremiums()
{
// Get the Cost Multiplier
$costMulti = $this->GetCostMultiplier();
// Get the Prem Ops
$premOps = $this->GetPremOpsEL();
// Get the Factors
$factors = $this->GetFactors();
// Get the full class array
$classArray = $this->GetClassArray();
foreach ($classArray as $key => $values) {
$classTotalHalved = $values / 1000;
$mainMultiplier = $costMulti * $premOps[$key] * $factors[$key]['premops'];
$premium = $classTotalHalved * $mainMultiplier;
$opsPremiums = array(
$key => round($premium)
);
}
return $opsPremiums;
}
I want $opsPremiums to not just iterate 1 at a time. I need it to iterate and add itself to itself.
I tried
foreach ($opsPremiums as $key2 => $values2) {
$opsPremiums = array(
$key => round($premium)
);
}
Can someone explain to me what I need to do in order to get the $opsPremium to stack itself neatly into a single array?
should be so
foreach ($opsPremiums as $key2 => $values2) {
$opsPremiums[] = array(
$key => round($premium)
);
}
I'm a little unsure of what you mean, but are you trying to return all the results in $opsPremium?
The issue is your setting it as an array on each iteration rather than adding to it.
$opsPremium = array();
foreach ($classArray as $key => $values) {
$classTotalHalved = $values / 1000;
$mainMultiplier = $costMulti * $premOps[$key] * $factors[$key]['premops'];
$premium = $classTotalHalved * $mainMultiplier;
$opsPremiums[] = array(
$key => round($premium)
);
}
return $opsPremiums;
Storing $opsPremium outside the loop and adding to it each time will do that for you.
My apologies if this is not what you were asking.
It seems your very confused with the terminology of how to speak about your problem. I believe what you should have asked is, I want to add some extra items including itself to an array for return. In which case the magic you need is array concatenation. Im a little unsure of what your array requires, but you can append anything to any php array with the [] operator. If you respond with a more detailed question perhaps I can help you further.
Depending on what your are adding to your array, for the program to function you may need to use the array_merge, array_push.

Categories