Can someone explain/annotate this Ruby snippet with comments? - ruby

Please explain this Ruby code so I can convert it to PHP:
data = Hash.new({})
mysql_results.each { |r| data[r['year']][r['week']] = r['count'] }
(year_low..year_high).each do |year|
(1..52).each do |week|
puts "#{year} #{week} #{data[year][week]}"
end
end

data = Hash.new({})
# create hash 'data'
mysql_results.each { |r| data[r['year']][r['week']] = r['count'] }
# maps each row from sql query to hash like this: data[2010][30] = 23
# So you can access 'count' from every year and week in very simple way
(year_low..year_high).each do |year|
# for (year = year_low; year <= year_high; year++)
(1..52).each do |week|
# for (week = 1; week <=52; week++)
puts "#{year} #{week} #{data[year][week]}"
# printf("%d %d %d\n", year, week, data[year][week]);
end
end
Sorry for mixing C with pseudo code, but I hope it helps!

The first bit is just forming an array like so:
$data[2009][17] = 10;
PHP equivalent of that would be:
foreach ($mysql_results as $r){
$data[$r['year']][$r['week']] = $r['count'];
}
The second part would equate to the following:
foreach(range($year_low, $year_high) as $year){
foreach(range(1, 52) as $week){
print $year.' '.$week.' '.$data[$year][$week]
}
}
Hope that helps :)

$data = array();
#Build an array of 'count' per year/week
foreach($mysql_results as $r) {
$data[$r['year']][$r['week']] = $r['count'];
}
#Loop through the $data variable, printing out the 'count' for each year in the array,
#and all 52 weeks that year
for($year = $year_min; $year <= $year_max; $year++) {
for($week=1; $week<=52; $week++) {
echo "$year $week {$data[$year][$week]}";
}
}
Note that year_low and year_high are variables undefined in the current snippet, but they should be known to you.
Also, $mysql_results should be an array containing all rows returned by the database.
In short, the following code does this:
Make an array grouped per year, then per week, containing the value 'count'
Loop through this array, displaying, in order, the year, the week, and the value for 'count', if any

Related

Backpack for Laravel charts, append sum to chart

As I'm trying to implement charts into Backpack for Laravel, I been stuck for a few hours on this problem. The following script gets the number of users created for each day and appends them to an array that is then shown on the charts.
for ($days_backwards = 7; $days_backwards >= 0; $days_backwards--) {
// Could also be an array_push if using an array rather than a collection.
$users = Users::whereDate('created_at', today()->subDays($days_backwards))->count();
$user[] = $users;
}
Every iteration of the loop adds a number to the array (or is it a collection??) so something like [2,5,10,9,...].
I would rather like to get the total amount of users that ever registered, incrementally for each day, so that the result would be someting like [2,7,17,26,...].
I figured I could add each iteration with array_sum() but it's not working. Is it an array anyways? Is there a way to append to this list the sum to its previous?
Well I kind of figured out!
$sum = 0;
for ($days_backwards = 7; $days_backwards >= 0; $days_backwards--) {
$users = Users::whereDate('created_at', today()->subDays($days_backwards))->count();
$sum = $sum + $users;
$user[] = $sum;
}
It works!

how to increment day by one to find the next desired day in laravel

I've an array of day name like ['Wednesday','Sunday','Monday']
now I want to find the next available dates That matched with the array from today's date. I want date. I tried for so long but none of them were successful. My code is given below
$datesAvailable = array();
$count = 0;
$dateToday = Carbon::now()->toDateTimeString();
//$avlDays is the array of day names
$avlDays = DB::table('doctor_schedules')
->select('available_days')
->where('department',$receivedDepartment)
->Where('doctor_id', $receivedDoctor)
->get();
for($k=5; $k > 0; $k++)
{
$dateToday = $dateToday->endOfWeek();
// $parsedDate = Carbon::parse($dateToday);
$dateTodayFormated = new Carbon($dateToday);
$nextDayName = $dateTodayFormated->englishDayOfWeek;
for($i = 0; $i <= 2; $i++)
{
if($avlDays === $nextDayName)
{
$datesAvailable[$count] = $nextDayName;
$count++;
}
}
}
return (['availableDates' => $dateToday]);
Solved
For the current date use
now()
https://laravel.com/docs/6.x/helpers#method-now
Carbon does this.
foreach ($avlDays as $day) {
$nextDay = Carbon::parse("next $day");
// do something with $nextDay...
}
So, assuming $avlDays is returning you a Carbon date range:
$avlDays = DB::table('doctor_schedules')
->select('available_days')
->where('department',$receivedDepartment)
->Where('doctor_id', $receivedDoctor)
->get()
->toArray();
The code below assumes that the array value from ['monday', 'tuesday' ...] is saved as $weekday.
If you are trying to find a specific date within a range that falls on a certain weekday, you can do something like:
$availableAppointments = [];
foreach ($avlDays as $day) {
if ($day->isDayOfWeek($weekday)) {
$availableAppointments[] = $day;
}
Then you can use $availableAppointments to list out the available dates on that day of the week.

Multiple array manipulations and merging

I am an amateur programmer that needs the help of a real one to resolve this beautiful problem, because I must admit that I am really stuck on this one!
In my database I have a « tslines » table that contains a value (sum_week) for a given week(startdate) and a given contract(contract_id)
The fields that are important are : sum_week, user_id , startdate and contract_id
I also have a « users » table, the important values are « first_name, last_name »
I have many workers that have worked on a contract, at different times (startdate, represents the first day of the week)
Example (table below): I can have 3 lines for worker A, and 2 lines for worker B
For some week(startdate), it can happend that no one worked on the contract
I want to show a table with those informations, for contract_id=3(ex) (this field is in tslines table) :
sum_week is a field, I don't want to recalculate with a SQL query
I don’t want to run a query for each weeks to check for each user if he worked on a contract because that would become a problem if I have ex : 30 weeks with 30 users that worked on the project..
I started by building an array of all possible « startdate »
//Selects min and max startdate of the tslines, use $dates->maxdate and ->mindate
$dates = $contract->tslines()->whereIsOfficial(true)->select(DB::raw('MAX(startdate) as maxdate, MIN(startdate) as mindate'))->first();
//Define first date declared in tslines
$loopdate = Carbon::parse($dates->mindate);
$maxdt = Carbon::parse($dates->maxdate);
//While loop to create array of date ranges from min to max
$date_count = 0;
$daterange = array();
while($loopdate->gt($maxdt) == false)
{
$daterange[] = $loopdate->format('Y-m-d');
$loopdate->addDays(7);
$date_count++;
}
I know I have to do some array manipulations but I really don’t know from where to start, even witht the queries..
I can get all the related tslines of contract by doing:
$contract->tslines()->get()
But I dont't know how to build an array that contains user information and all the startdate (even if he didn't work that week)
Can anybody give me some hints.. It would be greatly appreciated!!
Thanks in advance!
Raphaël
Let's start from what we know.
We know which users have worked on which contracts and on what date.
With your function above, we have the max date and the min date a user has started working on a contract.
Solution:
$tslines = $contract->tslines()->orderBy('user_id','ASC')->orderBy('startdate','ASC')->get();
//I didn't see any relationship calls to the user's object, so you'll have to add one of your own. I am assuming, your `tslines` has a relationship `user` here.
$userListResult = $contract->tslines()->with('user')->orderBy('user_id','ASC')->select(\Db::raw('distinct("user_id")')->get();
$dates = $contract->tslines()->whereIsOfficial(true)->select(DB::raw('MAX(startdate) as maxdate, MIN(startdate) as mindate'))->first();
$minDate = Carbon::parse($dates->mindate);
$maxDate = Carbon::parse($dates->maxdate);
//we flatten the array for future use.
$userList = array();
foreach($userListResult as $l)
{
$userList[$l->user_id] = $l->user->first_name.' '.$l->user->last_name;
}
//Assuming you are printing a table in blade
<table>
<?php
//Print the table headers
echo"<tr>
<td>User</td>";
$currDate = clone($minDate);
do
{
echo "<td>".$currDate->format('Y-m-d')."</td>";
$currDate->addDay();
}
while($currDate->diffInDays($maxDate) !== 0);
echo "</tr>";
//Print each user's row
foreach($userlist as $userid => $username)
{
echo "<tr>
<td>
$username
</td>";
$currDate = clone($minDate);
//loop through all the dates in range (min to max date)
do
{
$foundDate = false;
//We check if user has worked on that day
foreach($tslines as $row)
{
if($row->user_id === $userid && $row->startdate->format('Y-m-d') === $currDate->format('Y-m-d'))
{
//Print result if startdate & userid matches
echo "<td>{$row->sum_week}</td>";
$foundDate = true;
//Get out of the loops
break;
}
}
if(!$foundDate)
{
echo "<td>X (didn't work)</td>";
}
$currDate->addDay();
}
while($currDate->diffInDays($maxDate) !== 0);
echo "</tr>";
}
?>
</table>

Ruby .has_key? not seemingly working?

This is a strange problem, because I can write what looks like totally identical code in PHP that works fine, yet Ruby is failing without explanation. If someone could offer advice, I'd be really happy.
So I am iterating over a database table in Ruby. Every row has a date field. I want to generate a line graph from this table. So if there are 30 lines with "1995" in the date, I want my hash to end up with "1995": 30 as its content. Then I can feed that data to a JS chart library.
So my code right now is
db.execute("SELECT date FROM events") do |row|
graphdata = {}
year = row[0][0...4] # Gets first four digits of date, so 1995, 1996, 1997, etc.
if graphdata.has_key?(year) then
graphdata[year] += 1
else
graphdata[year] = 1
end
end
Pretty simple. If there's already a key for that year, increment it; if there's not, create it with an initial value of 1.
But the result I get is
{"1997"=>1}
{"1997"=>1}
{"1998"=>1}
{"1998"=>1}
{"1998"=>1}
{"1998"=>1}
{"1998"=>1}
{"1998"=>1}
I'm new to Ruby, but I can't understand why. The logic seems totally sound. I even wrote the same thing in PHP, which is working fine.
$results = $db->query("SELECT date from events order by date asc");
$graphdata= array();
while ($row = mysqli_fetch_row($results)) {
$year = substr($row[0],0,4);
if (array_key_exists($year,$graphdata)) {
$graphdata[$year]++;
} else {
$graphdata[$year] = 1;
}
}
What am I doing wrong?
Place graphdata = {} outside the main loop. Otherwise you are re-initializing it to the empty hash on each new row.
Also, you could probably just use a default value:
graphdata = Hash.new(0)
db.execute("SELECT date FROM events") do |row|
year = row[0][0...4] # Gets first four digits of date, so 1995, 1996, 1997, etc.
graphdata[year] += 1
end

Linq and conditional sum

I have a class and a list as below:
class C1
{
int RecType ...;
decimal Income ...;
decimal Outcome ...;
}
List<C1> myList ...;
The list is loaded with several records, and they have various values in RecType
What I want is to calculate total on Income and Outcome but only for a certain value of RecType
Here's a pseudo code of what I need to get
totalIncome = myList.Sum(Income).Where(RecType==1);
How can I accomplish this with linq?
Thank you
totalIncome = myList.Where(x => x.RecType == 1).Select(x => x.Income).Sum();
First you filter on the record type (Where); then you transform by Selecting the Income of each object; and finally you Sum it all up.
Or for a slightly more terse version:
totalIncome = myList.Where(x => x.RecType == 1).Sum(x => x.Income);
totalIncome = myList.Sum(c=>
(c.RecType==1 ? c.Income : 0));

Resources