Pretty new to PHP and i'm trying to achieve something, that in my opinion can be done easily in c#. However in PHP it isn't that easy to achieve for me.
When iterating over an XML file, I want to store all average scores per year.
The years will be unique, the scores should be their values.
Output should be like:
['2012'] => array(8.1, 7.3, 8.8)
['2013'] => array(6.7, 7.7, 5.5)
['2014'] => array(2.3, 7.9, 9.9)
This way I can get all average scores from the year 2014, etc.
In c# I would have created a Dictionary containing a List like:
var yearScores = new Dictionary<string, List<Decimal>>();
My current PHP code looks like:
$yearScores = array(array());
foreach($xml->results->children() as $result) {
//Reset variables
$current_date = null;
$current_average = null;
//Iterate over all 'answer' children in result
foreach($result->children() as $answer) {
//Retrieve Date and Average
if($average[0]['name'] == "date") {
$current_date = date('Y', strtotime($answer));
}
if($average[0]['name'] == "average") {
$current_average = $answer;
}
}
//Validate if we found both current Date and current Average
if(is_null($current_date) || is_null($current_average)) continue;
//The Date and Average exist
//See if the Datum already exists in our array
if(!in_array($current_date, $yearScores)) {
$yearScores[] = $current_date;
}
//The average should be added to the correct year in the array here.
}
How can I add the scores to the correct year arrays in the $yearScores array?
You can do it as follows:
// no need to initialize multidimensional array here
$yearScores = array();
foreach($xml->results->children() as $result) {
foreach($result->children() as $answer) {
//Retrieve Date and Average
// This here does not look right to me
if($average[0]['name'] == "date") {
$current_date = date('Y', strtotime($answer));
}
if($average[0]['name'] == "average") {
$current_average = $answer;
}
if(!isset($yearScores[$current_date])) {
$yearScores[$current_date] = array($current_average);
} else {
array_push($yearScores[$current_date], $current_average);
}
}
}
I am not sure about the ifs however (check my comment). Have you checked if their output is correct?
Related
I am trying to sort an array of activities based on their dates. For example:
"Do stuff" 2020-06-06
"Do more stuff" 2020-06-06
"Do even more" 2020-06-07
I now want to place these dates into a new array specifically for one date so an array for 2020-06-06 and an array for 2020-06-07 but the dates differ everytime so there it is no possible to make predifined arrays.
activityArray = CMS_GetActivity("1");
$activityList = array();
foreach ($activityArray as $tempActivity) {
array_push($activityList, $tempActivity);
}
$_SESSION['days'] = $activityList;
This is where i am now but I'm nowhere near where I wanted to be.
function GetActivity2(){
//get all activities from the database belonging to the volunteer
$activityArray = CMS_GetActivity("1");
//make an array for all the days
$dayList = array();
//foreach activity from the database
foreach ($activityArray as $tempActivity){
//set a success meter on fail.
//this success meter is set to success if the activity can be sorted in a day,
//if the activivty can not be classified, the success stays on fail a new day is made.
$sucessBool = false;
//for every day in the daylist
for ($i=0; $i < count($dayList); $i++) {
//if the day is not empty
if($dayList[$i] != NULL){
//grab one activity from the daylist
foreach ($dayList[$i] as $key) {
//if the date corresponds with the date from the activity gotten from the database
if (date("m-d-Y",strtotime($key->Time)) == date("m-d-Y",strtotime($tempActivity->Time))){
//place the activity in that day
array_push($dayList[$i], $tempActivity);
//and set the success meter on success
$sucessBool = true;
//break out of the loop so only one activity of the day has to be checked
break;
}
//break out of the loop to check for days
break;
}
}
}
//check if the success meter is on Fail
if($sucessBool == false){
//empty an array
$activityList = array();
//put the activity in the activitylist
array_push($activityList, $tempActivity);
//put the activitylist in the daylist
array_push($dayList, $activityList);
}
}
$_SESSION['days'] = $dayList;
}
This is my completed code, it is probably not the cleanest code but i'm fine with that.
I am trying to get the total amount collected in a month, let's say January.
I am able to retrieve all the created_at fields which were created in the month of January in the $main_data_January variable. The $main_data_January variable contains this type of results.
As you can see, each item has a field called amount.
Problem
I want to retrieve the value of amount field from each item and sum them up. As I'm doing it in the total_earnings_janunary, but this is where I am facing the problem.
By adding both the amounts, the expected result should be 13000, but
the result is 8000. It is only getting only the first value of amount after being in a loop.
$customers = Tag::all();
$total_earnings_janunary = 0;
$query_date = '2017-01-04';
$start_date_janunary = date('Y-01-01', strtotime($query_date));
$end_date_janunary = date('Y-m-t', strtotime($query_date));
foreach ($customers as $customer) {
if (Auth::User()->gym_code == $customer->gym_code ) {
$main_data_janunarys = DB::table('tags')->whereBetween('created_at', [$start_date_janunary,$end_date_janunary])->get();
}
}
for ($i=0; $i <= count($main_data_janunarys); $i++) {
$total_earnings_janunary = $total_earnings_janunary + $main_data_janunarys[$i]->amount;
dd($total_earnings_janunary);
}
Few things to note:
You're querying the Tag model and storing it in $customers. Resulting entities are not customers. Make sure that's intended.
In the first foreach loop, you are overwriting previous value of the $main_data_janunarys over and over. Use break if that's intended.
In the for loop, you are dding early. Move it outside the loop and you'll see your intended results. In the loop exit condition you should be using < instead of <= as you're starting from zero.
To sum up the collection you could just use Collection::sum() method, like: $main_data_janunarys->sum('amount');.
Try this:
$customers = Tag::all();
$total_earnings_janunary = 0;
$query_date = '2017-01-04';
$start_date_janunary = date('Y-01-01', strtotime($query_date));
$end_date_janunary = date('Y-m-t', strtotime($query_date));
foreach ($customers as $customer)
{
if( Auth::User()->gym_code == $customer->gym_code ) {
$main_data_janunarys = DB::table('tags')->whereBetween('created_at', [$start_date_janunary,$end_date_janunary])->get();
}
}
$total_earnings_january = $main_data_januarys->sum('amount');
You can read further about Laravel's Collection here
I am trying to do a stuff like playing ads based on interest of user. there are certain other parameters set by advertiser. If all those parameters match with a certain user profile then that ad has to be played to him,else check with the next ad..If the list of ad ends and none of them matched then remove one of the parameter and then match. finally if none of the parameters matched then play the ad which is at the top of the list. I have two seperate tables for user and ad, will it be good to join them and fetch data match?
Can anyone tell me which loop will best fit here?
This is what i have tried till now.
`public function adpreferences($ads,$userid){
for($i=0;$i<count($ads);$i++){
$sql="SELECT ua.ads,ua.frm_age,ua.t_age,ua.user_income,ua.user_occupation,ua.user_gender,U.gender,U.income,U.occupation, U.dob FROM user_ad ua LEFT JOIN users U ON U.userid =ua.userid where U.userid='$userid' AND ua.ads='$ads[$i]'";
$res=#mysql_query($sql);
$numOFRows =#mysql_num_rows($res);
if($numOFRows > 0){
while ($result = #mysql_fetch_assoc($res)){
$returnArr[]=$result;
$user_occ=$result['user_occupation'];
$user_incm=$result['user_income'];
$gen=$result['user_gender'];
$f_age=$result['frm_age'];
$t_age=$result['t_age'];
//print_r ($returnArr);
$dob= $result['dob'];
$birthdate = new DateTime($dob);
$today = new DateTime('today');
$age = $birthdate->diff($today)->y;
//print_r ($age);
//return (array($result));
for($i=0;$i<4;$i++){
for($j=0;$j<count($ads);$j++){
if ($ads[$j]!==0){
if(($user_occ==$result['occupation'])&&($user_incm==$result['income'])&&($gen==$result['gender'] || $gen =='Both')&&(($age>= $f_age) && ($age<= $t_age))){
$ads[]=$result['ads'];
}
return $ads[$j];
}
}
for($k=0;$k<count($ads);$k++){
if ($ads[$k]!==0){
if(($user_occ==$result['occupation'])&&($gen==$result['gender'])&&(($age>= $f_age) && ($age<= $t_age))){
$ads[]=$result['ads'];
return $ads[$k];
}
}
}
for($m=0;$m<count($ads);$m++){
if ($ads[$m]!==0){
if(($gen==$result['gender'])&&(($age>= $f_age) && ($age<= $t_age))){
$ads[]=$result['ads'];
return $ads[$m];
}
}
}
for($n=0;$n<count($ads);$n++){
if ($ads[$n]!==0){
if(($gen==$result['gender'])||($gen=='Both'))
{
$ads[]=$result['ads'];
return $ads[$n];
}
}
}
}
return $ads[0];
}
}
}
}``
As suggested i used foreach loop and tried this.
while ($result = #mysql_fetch_array($res)){
$dob= $result['dob'];
$birthdate = new DateTime($dob);
$today = new DateTime('today');
$age = $birthdate->diff($today)->y;
//print_r ($age);
foreach($result as $array){
for($i=0;$i<count($ads);$i++){
if(($array['user_occupation']==$array['occupation'])&& ($array['user_income']==$array['income']) && ($array['user_gender']==$array['fbgender'] || $array['user_gender']=='Both') && (($age>=$array['frm_age'])&&($age<=$array['t_age']))){
return $ads[$i];
break;
}
elseif(($array['user_occupation']==$array['occupation']) && ($array['user_gender']==$array['fbgender'] || $array['user_gender']=='Both') && (($age>=$array['frm_age'])&&($age<=$result['t_age']))){
//return $ads[$i];
break;
}
elseif(($array['user_gender']==$array['fbgender'] || $array['user_gender']=='Both') && (($age>=$array['frm_age'])&&($age<=$array['t_age']))){
//return $ads[$i];
break;
}
elseif(($array['user_gender']==$array['fbgender'] || $array['user_gender']=='Both')){
//return $ads[$i];
break;
}
else{
//return $ads[0];
}
}
}
But i am getting error like undefined variable $array and illegal offset 'user_occupation',illegal offset 'occupation' and so on...
I'd use a foreach() loop with a switch on the arguments, keep track of which ad and how many requirements were fullfilled, once the loop finished, get the best match and show it to the user
You could foreach through the ads and check a condition.
However, if there's a large number of ads you could consider storing them as an array (if not already) to foreach through, or even storing them in a DB (like mysql) and select ONLY the specifc ad needed (would be not doubt faster than foreach if there are a lot of ads to loop through). If mysql returns multiple results, you can fetch the results and loop through with a while loop.
How can I get the record values in the database to be sorted like this in an array. Supose I am adding the day no.
array
[0] => array=>'id'=>'26' 'date'=>'26'
[1] => array=>'id'=>'27' 'date'=>'27',
array=>'id'=>'28' 'date'=>'27',
array=>'id'=>'29' 'date'=>'27'
[2] => array=>'id'=>'30' 'date'=>'29'
[3] => array=>'id'=>'31' 'date'=>'31',
array=>'id'=>'32' 'date'=>'31',
array=>'id'=>'33' 'date'=>'31'
Basically, I want to add an array to the same index if the next id contains a record with the same date (day no) of the month. Otherwise add it normally.
Right now, My function is adding the rows of the record without sorting it in the format I want it to be in.
The reason I want it to be in this format is because, I need to run the foreach, and if 1 day contains 2 records, then it will append another <li> into my unordered list.
public function getArticles()
{
$sql = 'CALL getArticles()';
$articles = Array();
if (Model::getConnection()->multi_query($sql)) {
do {
if ($result = Model::getConnection()->store_result()) {
while ($row = $result->fetch_assoc()) {
array_push($articles,$row);
}
$result->free();
}
} while (Model::getConnection()->next_result());
}
return $articles;
}
I don't recognize what some of your code is doing, but I think this is the important part.
while ($row = $result->fetch_assoc()) {
if (!isset($articles[$row['date']])) {
$articles[$row['date']] = array();
}
$articles[$row['date']][] = $row;
}
The only difference will be that your array will be keyed on the date instead of incrementing from zero. If you really want it reindexed, you can do...
array_values($articles);
As savinger pointed out, there is alot of functionality in your code which I don't really know, so I've included comments to indicate whereabouts the process is:
// Start of your loop
// $value is what you're getting from the DB...
$array_search = array_search($value,$main_array);
if($array_search)
{
// If this value already exists, we need to add
// this value in +1 of its current value
$main_array[$array_search][] = $value + 1;
}
else
{
// Make a new array key and add in the value
$main_array[] = $value;
}
// End of your loop
In my database I have a table of "weeks" and a table of "workouts". I would like to achieve something like the following:
Week 1
workout 1 title
workout 1 content
workout 2 title
workout 2 content
workout 3......
week 2
workout 1 title
workout 1 content
workout 2 title
workout 2 content
workout 3......
week 3.....
I've trying something like:
function get_weekly_content() {
$user_id = $this->session->userdata('id');
$weeks = $this->db->select('week_no')->where('user_id', $user_id)->get('weeks');
if($weeks->num_rows > 0) {
foreach($weeks->result() as $row) {
$week_no = $row->week_no;
$workouts = $this->db->where('user_id', $user_id)->where('week_no', $week_no)->get('workouts');
if($workouts->num_rows > 0) {
foreach($workouts as $workout) {
$workout_data[] = $workout;
}
}
$weekly_data[] = $workout_data;
}
return $weekly_data;
}
}
but maybe I have the wrong idea. I would then also need to display the data.
EDIT my question is, what would be the best way to achieve the above and get and array/object to loop through on a view page?
Thanks
Looping with in a loop is just fine, and your approach is appropirate. However!
Generally speaking you shouldn't run mysql queries inside of loops if there is any way to avoid it because queries are quite slow this will really degrade the performance of your script. Otherwise, the idea is correct. Try to write a query outside of the loops that puts all the relevant user data into a keyed array and then pull the information from the array while you're looping.
You're going to see problems with this line: $weekly_data[] = $workout_data; if $workouts->num_rows > 0... if it's the first loop, it will throw an error because $workout_data won't be set, and if it's subsequent loops then on any week that doesn't have results, it will display the previous week's data. You can fix this by setting/resetting $workout_data at the top of the inner loop:
$workout_data = array();
if($workouts->num_rows > 0) {
foreach($workouts as $workout) {
$workout_data[] = $workout;
}
}
function get_weekly_content() {
$user_id = $this->session->userdata('id');
$weeks = $this->db->select('week_no')->where('user_id', $user_id)->get('weeks');
$weekly_data = array();
if($weeks->num_rows > 0) {
foreach($weeks->result() as $row) {
$workout_data = array();
$week_no = $row->week_no;
$workouts = $this->db->where('user_id', $user_id)->where('week_no', $week_no)->get('workouts');
if($workouts->num_rows > 0) {
foreach($workouts as $workout) {
$workout_data[] = $workout;
}
}
$weekly_data[$week_no] = $workout_data;
}
}
return $weekly_data;
}
Then access the data:
$weekly_data = get_weekly_content();
foreach( $weekly_data as $week_no => $workout_data){
// do something with it.
}
That being said, I agree with #Ben D, you should think about your query and create one that can return all the results at once.