well I have a working script (see below) but it seems quite clunky and redundant; in my defense I wrote this code many moons ago, but that's not the point. I was curious if anyone has an idea on a more efficient way of writing this code, with less loops and conditionals and, well, noise in the code.
Code in question:
private function pageLinks($num, $page = 1, $search = false, $ne = false) {
$query = ($search) ? '&query='.$search : null;
$by = (is_numeric($ne)) ? '&by='.$ne : null;
$links = 'Page(s):1';
$count = 1;
$npp = $this->numPerPage;
$buttons = 9;
$half = 4;
for($i = 1; $i <= $num; $i++) {
if(($i%$npp) === 0) {
$count++;
}
}
if($count < $buttons) {
for($i = 2; $i <= $count; $i++) {
$links .= '' . $i . '';
}
} elseif($page <= ($half + 2)) {
for($i = 2; $i <= $buttons; $i++) {
$links .= '' . $i . '';
}
$links .= '...' . $count . '';
} elseif($page <= ($count - ($half + 2))) {
$links .= '...';
for($i = $half; $i > 0; $i--) {
$links .= '' . ($page - $i) . '';
}
$links .= '' . ($page - $i) . '';
for($i = 1; $i <= $half; $i++) {
$links .= '' . ($page + $i) . '';
}
$links .= '...' . $count . '';
} else {
$links .= '...';
for($i = $buttons - 1; $i >= 0; $i--) {
$links .= '' . ($count - $i) . '';
}
}
return($links);
}
The method is called like so:
$links = $this->pageLinks($count, $page, $url, $ne);
And the variables are as such:
$count = total number of clients in database (int)
$page = current page to build from (int)
$url = the name or email for the search (String)
$ne = is for the search string either by name (1) or email (2) (int)
And the output is something like (as links):
Page(s):1 2 3 4 5 6 7 8 9...33
Or if you're in the middle (page 20):
Page(s):1...16 17 18 19 20 21 22 23 24...33
Now this isn't always called through a search function, hence the default values for $url and $ne, but that's not very important. My question is there a cleaner way to handle building of these links? Or am I stuck with this cluster of loops?
With the help of the people at codereview.stackexchange.com I found exactly what I needed. You can find the answer here for a more in-depth approach, but here is the updated code if anyone comes across this and is curious:
private function pageLinks($num, $page = 1, $search = false, $ne = false) {
$query = ($search && is_numeric($ne)) ? "&query=" . $search . "&by=" . $ne : null;
$links = "Page(s):" . $this->page_link(1, $query);
$npp = $this->numPerPage;
$half = 4;
$count = floor($num / $npp) + 1;
$from = $page - $half;
if($from <= 2) {
$from = 2;
}
$to = $page + $half;
if($to >= $count - 1) {
$to = $count - 1;
}
if($from > 2) {
$links .= "...";
}
for($i = $from; $i <= $to; $i++) {
$links .= $this->page_link($i, $query);
}
if($i < $count) {
$links .= "...";
}
$links .= $this->page_link($count, $query);
return($links);
}
private function page_link($num, $query) {
return("" . $num . "");
}
Related
I am using Laravel 8 to create an application. Here I need to Generate an Order Number for every order. For this, I use Helper and write this code. It works the very first time, from the second time it shows "Undefined variable $last_number" from return line.
public static function OrderNumberGenerator($model, $trow, $length = 4, $prefix)
{
$data = $model::orderBy('id', 'desc')->first();
if (!$data) {
$og_length = $length;
$last_number = '';
} else {
$code = substr($data->$trow, strlen($prefix) + 1);
$actual_last_number = ($code / 1) * 1;
$increment_last_number = $actual_last_number + 1;
$last_number_length = strlen($increment_last_number);
$og_length = $length - $last_number_length;
$last_number_length = $increment_last_number;
}
$zeros = "";
for ($i = 0; $i < $og_length; $i++) {
$zeros .= "0";
}
return $prefix . '-' . $zeros . $last_number;
}
from my controller I use this:
Helper::OrderNumberGenerator(new OrderDetail, 'orderNo', 5, 'DRW');
public static function OrderNumberGenerator($model, $trow, $length = 4, $prefix)
{
$last_number = '';
$data = $model::orderBy('id', 'desc')->first();
if (!$data) {
$og_length = $length;
} else {
$code = substr($data->$trow, strlen($prefix) + 1);
$actual_last_number = ($code / 1) * 1;
$increment_last_number = $actual_last_number + 1;
$last_number = strlen($increment_last_number);
$og_length = $length - $last_number;
$last_number = $increment_last_number;
}
$zeros = "";
for ($i = 0; $i < $og_length; $i++) {
$zeros .= "0";
}
return $prefix . '-' . $zeros . $last_number;
}
I think your code should be like that. I hope it is help you.
You must define
$last_number = ' ';
before if statement
When it exits from the if block, this variable is deleted from memory
I'm using an calendar rendering library (simplecalender/donatj) for one of my projects but I can't figure out how to display only the days left of current month and not the full month.
As far as I understand, this is the part that builds the calender:
public function show( $echo = true ) {
if( $this->wday_names ) {
$wdays = $this->wday_names;
} else {
$today = (86400 * (date("N")));
$wdays = array();
for( $i = 0; $i < 7; $i++ ) {
$wdays[] = strftime('%a', time() - $today + ($i * 86400));
}
}
$this->arrayRotate($wdays, $this->offset);
$wday = date('N', mktime(0, 0, 1, $this->now['mon'], 1, $this->now['year'])) - $this->offset;
$no_days = cal_days_in_month(CAL_GREGORIAN, $this->now['mon'], $this->now['year']);
If I change no_days to 25 only days 1-25 are displayed within the calendar. So almost what I want.
Any idea how I can display 25 to 31 only (days left for July)?
Thanks.
Here's the rest of the code:
$out = '<table cellpadding="0" cellspacing="0" class="SimpleCalendar"><thead><tr>';
for( $i = 0; $i < 7; $i++ ) {
$out .= '<th>' . $wdays[$i] . '</th>';
}
$out .= "</tr></thead>\n<tbody>\n<tr>";
$wday = ($wday + 7) % 7;
if( $wday == 7 ) {
$wday = 0;
} else {
$out .= str_repeat('<td class="SCprefix"> </td>', $wday);
}
$count = $wday + 1;
for( $i = 1; $i <= $no_days; $i++ ) {
$out .= '<td' . ($i == $this->now['mday'] && $this->now['mon'] == date('n') && $this->now['year'] == date('Y') ? ' class="today"' : '') . '>';
$datetime = mktime(0, 0, 1, $this->now['mon'], $i, $this->now['year']);
$out .= '<time datetime="' . date('Y-m-d', $datetime) . '">' . $i . '</time>';
$dHtml_arr = false;
if( isset($this->dailyHtml[$this->now['year']][$this->now['mon']][$i]) ) {
$dHtml_arr = $this->dailyHtml[$this->now['year']][$this->now['mon']][$i];
}
if( is_array($dHtml_arr) ) {
foreach( $dHtml_arr as $dHtml ) {
$out .= '<div class="event">' . $dHtml . '</div>';
}
}
$out .= "</td>";
if( $count > 6 ) {
$out .= "</tr>\n" . ($i != $count ? '<tr>' : '');
$count = 0;
}
$count++;
}
$out .= ($count != 1 ? str_repeat('<td class="SCsuffix"> </td>', 8 - $count) : '') . "</tr>\n</tbody></table>\n";
if( $echo ) {
echo $out;
}
return $out;
}
private function arrayRotate( &$data, $steps ) {
$count = count($data);
if( $steps < 0 ) {
$steps = $count + $steps;
}
$steps = $steps % $count;
for( $i = 0; $i < $steps; $i++ ) {
array_push($data, array_shift($data));
}
}
I try create a simple system blog page with this algorithm:
<?php
$page = floor(10 / 10);
$limit = 40;
$num= 100;
$page = 1;
for ($record = 0; $record <= $num ; ++$record )
{
if($record % $limit == 0)
{
if(!($record < $limit))
{
echo 'page:'.$page.'<br/>';
for($id = $record - $limit +1 ; $id <= $record ; ++$id)
{
echo $id.'<br/>';
}
$page ++;
echo '<hr>';
}
}
}
?>
but it seems do not work for example... on $limit=40 I lost last 20 id!
can help me to improve this algorithm or suggest me a better way>
<?php
$limit = 40;
$items = 100;
$page_counter = 1;
$excess_items = $items % $limit;
if($excess_items > 0)
$total_page = ($items / $limit) + 1;
$current_count = 1;
while($page_counter <= $total_page){
echo 'total_page:'.$page_counter.'<br/>';
$cutting_count = 1;
while($cutting_count <= $limit){
if($current_count <= $items)
echo $current_count.'<br/>';
$cutting_count ++;
$current_count ++;
}
echo '<hr>';
$page_counter++;
}
?>
I have an array/string/integer of 7 flags, one for each day of the week (of a recurring event). How can I convert this to a brief list of the days?
So, for example
Given 1011001, return 'Su, T-W, Sa'.
Given 0111011, return 'M-W, F-Sa'.
What's the shortest way to accomplish this?
EDIT
For comparison, here's my own inelegant code:
<?php
function dowstring($dow) {
if ($dow == 0) return "Error";
$ddow = ["Su", "M", "T", "W", "Th", "F", "Sa"];
$t = strrev( sprintf('%07b', $dow) );
$u = str_split($t);
$out = '';
$cu = count($u);
$nn = 0; // number of days thus far counted
$v = 0; // number in the run
for($i = 0; $i < $cu; $i++) {
if ($u[$i]) {
if ($v == 0) {
$out .= ($nn) ? ", " : '';
$out .= $ddow[$i];
}
$nn++;
$v++;
}
else {
if ($v > 1) {
$out .= ($nn) ? "-" . $ddow[$i-1] : '';
}
$v = 0;
}
}
// in case Saturday is part of a run
if ($v > 1) {
$out .= ($nn) ? "-" . $ddow[$i-1] : '';
}
return $out;
}
echo "<pre>";
// testing script
for ($i = 1; $i < pow(2, 7); $i++) {
$ds = dowstring($i);
$j = strrev( sprintf("%07b", $i) );
printf("%s %s\n", $j, $ds);
}
echo "</pre>";
?>
EDIT
Another attempt, inspired by Prasanth:
function dowstring($dow) {
if ($dow == 0) return "Error";
$ddow = ["Su", "M", "T", "W", "Th", "F", "Sa"];
$t = strrev( sprintf('%07b', $dow) );
$v = array_keys( array_filter( str_split($t) ) );
$cv = count($v); $w = array();
$out = $ddow[$v[0]];
for ($i = 1; $i < $cv; $i++) $w[] = $v[$i] - $v[$i - 1] - 1;
$w = ( $cv == 1 ) ? array($w) : $w;
for ($i = 1; $i < $cv; $i++) {
if (!$w[$i - 1]) $last = $ddow[$v[$i]];
else {
if ( isset($last) ) $out .= '-' . $last;
$out .= ', ' . $ddow[$v[$i]];
unset($last);
}
}
if ($i > 1 && !$w[$i-2] ) $out .= '-' . $ddow[ $v[$i-1] ];
return $out;
}
I'd like to see something better. Anyone?
Try this:
$days=array('1'=>'Monday','2'=>'Tuesay','3'=>'Wednesday','4'=>'Thursday','5'=>'Friday','6'=>'Saturday','7'=>'Sunday');
$pattern = '1000110';
$arr1 = str_split($pattern);
$i=0;
foreach($days as $key => $tes) {
if($key - $arr1[$i] != $key) {
echo $tes;
}
$i++;
}
Adjust days array according to the sequence of days you want
Try this :
<?php
$days = array('Su','M','T','W','Th','F','Sa');
function checkConsec($d) {
for($i=0;$i<count($d);$i++) {
if(isset($d[$i+1]) && $d[$i]+1 != $d[$i+1]) {
return false;
}
}
return true;
}
$str = '0111011';
$array = array_keys(array_filter(str_split($str)));
$temp = array();
$res = array();
for($i=0;$i<count($array);$i++){
$temp[] = $array[$i];
if(checkConsec($temp) && count($temp) > 1){
$res[$temp[0]] = $days[$temp[0]]."-".$days[$temp[count($temp)-1]];
}else{
$res[$array[$i]] = $days[$array[$i]];
$temp = array();
$temp[] = $array[$i];
}
}
echo implode(",",$res);
?>
I have a for loop and inside of it I have a if statement something like this:
$output = "";
$limit = 550;
for ($i = 1; $i <= $limit; $i++) {
if($i < 10){
$output .= my_function($i*1);
}elseif($i < 20){
$output .= my_function($i*2);
}elseif($i < 30){
$output .= my_function($i*3);
}
//elseif 30 => 550
}
Problem is I find it very tedious to have to continue this elseif statement down to 550. Is there any way to do this without writing 55 elseif statements.
Your thinking is exactly right. Having to repeat that much code is a sure sign that something is off.
In this case, the solution is pretty simple. You just want to use integer division to knock off the ones digit, which you don't care about. You also need to adjust by one since you're checking less than and not less than or equal.
$output = "";
$limit = 550;
for ($i = 1; $i <= $limit; $i++) {
$temp = (int) ($i / 10) + 1;
$output = my_function($i*$temp);
}
for ($i = 1;$i <= 550;$i++) {
$multiplier = (int) ($i / 10) + 1;
$output = my_function($i * $multiplier);
}
My first thought is that you could use:
$output = "";
$c = 0;
$limit = 550;
for ($i = 1; $i <= $limit; $i++) {
if (($i + 1) % 10 == 0) {
$c++;
$output = my_function($i*$c);
}
}
How about
$output = "";
$limit = 550;
for ($i = 1; $i <= $limit; $i++) {
$num = ($i / 10) + 1
$output = my_function($i*$num);
}
Try this:
$output = "";
$limit = 550;
for ($i = 1; $i <= $limit; $i++)
{
$output = my_function($i * (1 + (int)($i / 10)));
}
The solution should be as simple as the following:
$output = "";
$limit = 550;
for ($i = 1; $i <= $limit; $i++)
{
$num = ceil($i/10);
$output = my_function($num, $num-1);
}
hmm the original code seems to have changed since I started typing this. The my_function function now only has 1 input when it originally had 2.
for ($i = 1; $i <= $limit; $i++) {
$output = my_function(i*floor($i/10+1));
}
Point is not really about this question:
You reassign output on every loop iteration, but only last will be vailable after loop? Need you $output[]= or $output.= ?