php - Return array based on range key - php

I have an array with of enumerating numbers, like:
$pageNumbers = array(1,2,3,4,5,6,7,8,9,10);
Now I have an active page number $currentPage and want to have based on this, before and after 2 elements - a total number of 5.
$currentPage = 2:
Return: array(1,2,3,4,5)
$currentPage = 6
Return: array(4,5,6,7,8)
$currentPage = 10
Return: array(6,7,8,9,10)
Unfortunately, I did not come up with an elegant and simple method to solve this (2x while, 1 big foreach and so on). Maybe you have an idea.
My first idea was:
foreach ($pageNumbers as $page) {
if($page < $currentPage+3 && $page > $currentPage-3) {
array_push(...);
}
}
This will work for the $currentPage = 6, but if $currentPage = 1, it will only return 1,2,3.

Use array_slice and cut out the part of the array you need.
I use an if to see where to slice the array.
if($currentPage < 3){
$arr = array_slice($pageNumbers,0,5);
}elseif($currentPage > count($pageNumbers)-2){
$arr = array_slice($pageNumbers,-5,5);
}else{
$arr = array_slice($pageNumbers,$currentPage-3,5);
}
See working example below.
https://3v4l.org/fpOFQ

Related

Get numbers next and after a certain number with dynamic max results with PHP

I have a pagination which renders some pages. I have a setting where the user can define how many pages are to be displayed as numbers in the pagination nav. The first and last number are always visible. Now if the user wants to have 3 numbers on the nav and assuming that i am now in the page 7, then it should look like this:
1 ... 6 7 8 ... 12
If the user wants four items then it should look like that:
1 ... 6 7 8 9 ... 12
Up until now i have the following which gives me 3 before and after the current page
$maxLinks = 3;
$currentPageNumber = 7;
$pages = [];
$pages[] = 1;
for($i = max(2, $currentPageNumber - $maxLinks); $i <= min($currentPageNumber + $maxLinks, 12 - 1); $i++) {
$pages[] = $i;
}
$pages[] = 12;
foreach ($pages as $key => $page) {
$newPage = '...';
if (($key === 0) && $pages[1] !== $page + 1) {
array_splice( $pages, 1, 0, $newPage );
}
$itemBeforeLast = count($pages)-2;
if (is_numeric($pages[$itemBeforeLast]) && ($key === $itemBeforeLast) && $pages[$itemBeforeLast + 1] !== $pages[$itemBeforeLast] + 1) {
array_splice( $pages, $itemBeforeLast +1, 0, $newPage );
}
}
This gives me back the following:
But i only want to get 3 or 4 numbers between the dots (this changes based on the value that the user gives in the settings ($maxLinks variable))
Any help is deeply appreciated
Best regards
As you add them to both sides, you need to divide by 2. Also, remove 1 to account for the current page. Then you just need to account for the possibility of having a non-even number of links to the left&right by rounding (down for the left, up for the right).
And end up with:
for($i = max(2, $currentPageNumber - floor(($maxLinks-1)/2));
$i <= min($currentPageNumber + ceil(($maxLinks-1)/2), 12 - 1); $i++)

How to make php generate random numbers untill the specific number is reached

I want a random integer to be generated in the range from 1 to 3 until 2 will be generated.
Please review the code below - What am I doing wrong?
Thank you!
<?php
$min = 1;
$max = 3;
$number = rand($min,$max);
while($number !== 2) {
echo ($number);
}
?>
your rand() is not in the while loop, so the rand() will execute one time.
If the $number is not 2, the while loop will execute without stoping.
If the $number is 2, the while loop will not executed.
while(($number = rand($min, $max)) != 2){echo $number;}

How to tell if a comma delimited list of numbers obeys the natural order of numbers

I have a comma delimited list of numbers which i am converting into an array and what i want to know about the list of numbers is if the numbers listed obey a natural ordering of numbers,you know,have a difference of exactly 1 between the next and the previous.
If its true the list obeys the natural ordering,i want to pick the first number of the list and if not the list obeys not the natural order,i pick the second.
This is my code.
<?php
error_reporting(0);
/**
Analyze numbers
Condition 1
if from number to the next has a difference of 1,then pick the first number in the list
Condition 2
if from one number the next,a difference of greater than 1 was found,then pick next from first
Condition 3
if list contains only one number,pick the number
*/
$number_picked = null;
$a = '5,7,8,9,10';
$b = '2,3,4,5,6,7,8,9,10';
$c = '10';
$data = explode(',', $b);
$count = count($data);
foreach($data as $index => $number)
{
/**
If array has exactly one value
*/
if($count == 1){
echo 'number is:'.$number;
exit();
}
$previous = $data[($count+$index-1) % $count];
$current = $number;
$next = $data[($index+1) % $count];
$diff = ($next - $previous);
if($diff == 1){
$number_picked = array_values($data)[0];
echo $number_picked.'correct';
}
elseif($diff > 1){
$number_picked = array_values($data)[1];
echo $number_picked.'wrong';
}
}
?>
The problem i am having is to figure out how to test the difference for all array elements.
No loops are needed, a little bit of maths will help you here. Once you have your numbers in an array:
$a = explode(',', '5,7,8,9,10');
pass them to this function:-
function isSequential(array $sequence, $diff = 1)
{
return $sequence[count($sequence) - 1] === $sequence[0] + ($diff * (count($sequence) - 1));
}
The function will return true if the numbers in the array follow a natural sequence. You should even be able to adjust it for different spacings between numbers, eg 2, 4, 6, 8, etc using the $diff parameter, although I haven't tested that thoroughly.
See it working.
Keep in mind that this will only work if your list of numbers is ordered from smallest to largest.
Try using a function to solve this... Like so:
<?php
error_reporting(0);
/**
Analyze numbers
Condition 1
if from number to the next has a difference of 1,then pick the first number in the list
Condition 2
if from one number the next,a difference of greater than 1 was found,then pick next from first
Condition 3
if list contains only one number,pick the number
*/
$number_picked = null;
$a = '5,7,8,9,10';
$b = '2,3,4,5,6,7,8,9,10';
$c = '10';
function test($string) {
$data = explode(',', $string);
if(count($data) === 1){
return 'number is:'.$number;
}
foreach($data as $index => $number)
{
$previous = $data[($count+$index-1) % $count];
$current = $number;
$next = $data[($index+1) % $count];
$diff = ($next - $previous);
if($diff == 1){
$number_picked = array_values($data)[0];
return $number_picked.'correct';
}
elseif($diff > 1){
$number_picked = array_values($data)[1];
return $number_picked.'wrong';
}
}
}
echo test($a);
echo test($b);
echo test($c);
?>
You already know how to explode the list, so I'll skip that.
You already handle a single item, so I'll skip that as well.
What is left, is checking the rest of the array. Basically; there's two possible outcome values: either the first element or the second. So we'll save those two first:
$outcome1 = $list[0];
$outcome2 = $list[1];
Next, we'll loop over the items. We'll remember the last found item, and make sure that the difference between the new and the old is 1. If it is, we continue. If it isn't, we abort and immediately return $outcome2.
If we reach the end of the list without aborting, it's naturally ordered, so we return $outcome1.
$lastNumber = null;
foreach( $items as $number ) {
if($lastNumber === null || $number - $lastNumber == 1 ) {
// continue scanning
$lastNumber = $number;
}
else {
// not ordened
return $outcome2;
}
}
return $outcome1; // scanned everything; was ordened.
(Note: code not tested)
To avoid the headache of accessing the previous or next element, and deciding whether it still is inside the array or not, use the fact that on a natural ordering the item i and the first item have a difference of i.
Also the corner case you call condition 3 is easier to handle outside the loop than inside of it. But easier still, the way we characterize a natural ordered list holds for a 1-item list :
$natural = true;
for($i=1; $i<$count && $natural; $i++)
$natural &= ($data[$i] == $data[0] + $i)
$number = $natural ? $data[0] : $data[1];
For $count == 1 the loop is never entered and thus $natural stays true : you select the first element.

Multiple counters not counting ( foreach / ifs)

This is my first StackOverFlow post.
I have an array of numbers, which I shuffle:
$nums = array("1","1","1","1","1","2","2","2","2","3","3","3","4","4","4");
shuffle($nums);
I am trying to identify a sequence/pattern of any three 3 identical numbers in a row in the shuffled array and
output the combined total of all sets of matching numbers.
The problem that I am running into seems to stem from attempting to compare the current number in the loop with the previous number (to see if they match).
When I echo the "previous" number it always outputs as "0". Thus I am unable to compare the current number and old number, which means I am not able to sum identify and sum a pattern of identical numbers.
Here is my code:
<?php
$t3count = 0;
$oldnum = 0;
$tots = 0;
$nums = array("1","1","1","1","1","2","2","2","2","3","3","3","4","4","4");
shuffle($nums);
foreach ($nums as $num) {
echo "$num: [$oldnum] ";
if ($num = $oldnum) {
$t3count++;
if ($t3count = 3) {
$tots = $num * $num;
$t3count = 0;
$oldnum = $num;
} else {
# do nonum
}
}
else {
$oldnum = $num;
}
# echo "<li>$num</li>";
}
echo "Your total is: $tots";
unset($num);
?>
Thank you.
You need to do comparison == not assignment = here:
if ($num = $oldnum)
and here:
if ($t3count = 3)
also this is probably going to bite you if i got the logic right
$t3count++;
if ($t3count == 3) {
how do you know which one counted to 3, id build nested arrays of like values first then process that.
you missed == to compare if ($num = $oldnum) and if ($t3count = 3)
replace with
if ($num == $oldnum)
if ($t3count == 3)

Algorithm to separate pagination display by ...?

Have an $A is the data for pagination:
$A = array(
0=>array(
0=>1,
1=>2
),
1=>array(
0=>3,
1=>5,
2=>2
),
2=>array(
0=>3,
1=>1,
2=>6,
3=>6
)
);
Anybody could help me to get the expected ouput (output this "...." more) the most important ?
.... told that it is still more element need to display next page.
or it the remain element from previous page.
There are 09 elements of $A to display ,So
I set
$show_per_page = 3;
Output (for the first page):
1
2
Total:3
3
....//output this "...." more
Output (for the second page):
....//output this "...." continue from first page
5
2
Total:10
3
.... //output this "...." more
Output (for the third page):
.... //output this "...." continue from second page
1
6
6
Total:16
if I set
$show_per_page = 5;
Output (for the first page):
1
2
Total:3
3
5
2
Total:10
// .... //not output this "...." more now
Output (for the second page):
3
1
6
6
Total:16
if I set
$show_per_page = 9;
OUTPUT:
1
2
Total:3
3
5
2
Total:10
3
1
6
6
Total:16
Currently I am try to do with the function paging_from_multi_arr but I am stuck on how implement to got the expeted result:
// page to show (1-indexed)
// number of items to show per page
function paging_from_multi_arr($display_array, $page){
Global $show_per_page;
$start = $show_per_page * ($page-1);
$end = $show_per_page * $page;
$i = 0;
foreach($display_array as $main_order=>$section){
$total = 0;
foreach($section as $sub_order=>$value){
if($i >= $end){
break 2; // break out of both loops
}
$total += $value;
if($i >= $start){
echo $value.'<br>';
}
$i++;
}
if($i >= $start){
echo 'Total:'.$total.'<br>';
}
if($i >= $end){
break;
}
}
$total = count($display_array, COUNT_RECURSIVE);
// Total numbers of elements in $display_array array.
// See http://php.net/manual/en/function.count.php
if ($end < $total){
echo "...";
}
}
$show_per_page = 5;
paging_from_multi_arr($A,$_GET["page"]);
Do you have any idea with the function here? Or could give the better algorithm?
thanks
This should give you the output you're looking for:
function flatten_display_array($display_array){
$new_array = array();
$count = 0;
foreach($display_array as $main_order => $section){
$total = 0;
foreach($section as $sub_order => $value){
$new_array[] = array('main' => $main_order,
'sub' => $sub_order,
'value' => $value);
$total += $value;
$count++;
}
// Add section's total to final element in section
$new_array[$count-1]['total'] = $total;
}
return $new_array;
}
function paging_from_multi_array($display_array, $page = 1, $show_per_page = 3){
if(isset($_GET['page']) && is_numeric($_GET['page'])){
// Page number set externally
$page = $_GET['page'];
}
if(isset($_GET['per_page']) && is_numeric($_GET['per_page'])){
// Per page set externally
$show_per_page = $_GET['per_page'];
}
$start = $show_per_page*($page-1);
$end = $show_per_page*$page;
// Convert array to useable format
$new_array = flatten_display_array($display_array);
/* Formatting elements */
$top_string = '....'; // Indicator continues is on previous page
$bottom_string = '....'; // Indicator continues on next page
$br = '<br />'; // Line break
$indent = ' '; // Indent of value row
$count = 0;
$string = '';
for($i = $start; $i < $end; $i++){
// Loop through visible range
$string .= $indent.$new_array[$i]['value'].$br;
if(isset($new_array[$i]['total'])){
$string .= 'Total: '.$new_array[$i]['total'].$br;
}
}
// Check previous page
if($start > 0 && $start < count($new_array) && !isset($new_array[$start-1]['total'])){
// Started mid-way through section
$string = $top_string.$br.$string;
}
// Check next page
if($end-1 < count($new_array) && !isset($new_array[$end-1]['total'])){
// Stopped mid-way through section
$string .= $bottom_string.$br;
}
return $string;
}
To use it, just call the paging_from_multi_array() function:
echo paging_from_multi_array($A);
This way, if the page number or the amount to show per page is not set, it will default to the ones set in the first line of paging_from_multi_array() (currently page 1 and 3 per page).
Also, look at the lines under /* Formatting Elements */ to set the elements for the output (eg: the '...' before and after each segment.
Without the "total" calculation, it should be a simple pagination (by merging the sub-arrays and paginate on the big array). But actually, "total" has nothing to do with the pagination itself. So I recommending let's first forget the "total" for paginating, then insert it in approriate place later.
My idea begins with creating a merge-array like this:
$B = array(
0=>1,
1=>2
0=>3,
1=>5,
2=>2
0=>3,
1=>1,
2=>6,
3=>6
}
And another array to keep track of the beginning of each sub-array of $A in the merge-array $B:
$C = {0, 2, 5}
Then I can do the pagination pretty simply as usual. About the "total", we can use the original array A to calculate it, then insert into the approriate position based on C.
For a quick example, at page 2, max-per-page = 3
From B, I get the sub-array B1 : B(offset = 1, max-per-page=3, from B[3] to B[5])
$B1 = {
1=>5,
2=>2,
0=>3
}
Based on $C={0,2,5}, by a simple "for" loop, we can have $C[1] = 2 < 3 < 5 = 5 = $C[2] < length(B), so at here we know that we will show 2 sub-array (A[1] and a[2]); and we must calculate and return total(A[1]) as well.
That's my idea. I think it would make things easier to keep track.

Categories